Exception is not being logged/throwed inside of completable future - java

I just realised that exception inside of whenComplete, in completable future is not being logged/throwed. Can someone explain that? How to properly use whenComplete?
public static void main(String[] args) {
var c = CompletableFuture.runAsync(() -> {
System.out.println("done");
});
c.whenComplete((unused, throwable) -> {
System.out.println((5/0));
throw new RuntimeException("I am throwing an exception");
});
System.out.println("ok");
}
output of this block of code
done
ok

From the docs (emphasis mine)
public CompletableFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action)
Description copied from interface: CompletionStage
Returns a new CompletionStage with the same result or exception as this stage, that executes the given action when this stage completes.
When this stage is complete, the given action is invoked with the result (or null if none) and the exception (or null if none) of this stage as arguments. The returned stage is completed when the action returns. If the supplied action itself encounters an exception, then the returned stage exceptionally completes with this exception unless this stage also completed exceptionally.
whenComplete returns a new CompletableFuture. CompletableFuture keeps track of what exception (if any) has occurred and expects you to deal with it. By ignoring the return value, you're suppressing the exception.
To wait on the result of the future, or throw if it throws, use join.
c.whenComplete((unused, throwable) -> {
System.out.println((5/0));
throw new RuntimeException("I am throwing an exception");
}).join();

Related

CompletableFuture does not complete on timeout

I have a method read that reads from input stream. I want to complete the future if read has not finished after timeout.
public static void main(String[] args) {
CompletableFuture<?> future = new CompletableFuture<>();
future
.thenRunAsync(() -> {
try {
read(data);
} catch (IOException e) {
future.completeExceptionally(e);
}
})
.orTimeout(1, TimeUnit.SECONDS);
future.join();
}
But when I run this code, it does not finish by timeout and waits for input stream anyway.
There's at least two problems with your code:
Nothing is being executed. You create a CompletableFuture and then invoke thenRunAsync on it. The stage created by thenRunAsync will only trigger once the previous stage has completed. Since you never complete the original CompletableFuture this will never happen. You also end up joining on a future that will never complete.
You're joining on the wrong CompletableFuture. Methods such as thenRunAsync and orTimeout return a new instance which creates a sort of "chain" of stages. Each stage is triggered by the completion of its "parent" stage. To fully understand this I recommend reading the documentation of CompletionStage.
Here's an example of your code working how I suspect you want:
public static void main(String[] args) {
CompletableFuture.runAsync(
() -> {
try {
read(data);
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
})
.orTimeout(1L, TimeUnit.SECONDS)
.join();
}
Some notes:
Used CompletableFuture#runAsync(Runnable) to create a "primordial" stage. This stage will complete when the Runnable completes and the common ForkJoinPool is used to execute the Runnable.
If and when thrown, the UncheckedIOException in the runAsync stage will cause the stage to complete exceptionally.
The #join() method is invoked on the instance returned by the orTimeout(1L, TimeUnit.SECONDS) call. Now if the timeout elapses the call to join() will throw a CompletionException wrapping a TimeoutException.
Warning: The call to read is not interrupted1 when the timeout elapses, meaning it will continue to execute in the background. This is due to the fact CompletableFuture has no reference to the executing threads and thus cannot interrupt them.
1. Assuming an interruption would even have an effect.

How to find CompletableFuture completed execeptionally

I am using CompletableFuture and have a question on exception handling.
I have a code like this, if any of validate() or process() method throws an exception then it is handled by the ExceptionHandler. However when I am using the CompletableFuture like this then the exception thrown is wrapped in CompletionException. May I know how can I make sure that my ExceptionHandler is called there instead of getting CompletionException?
CompletableFuture<Response> response = CompletableFuture
.supplyAsync(() -> {
validationService.validate(request);
return myService.process(request, headers);
});
Before calling get() on CompletableFuture call this method isCompletedExceptionally, will return true if it completes with exception
public boolean isCompletedExceptionally()
Returns true if this CompletableFuture completed exceptionally, in any way. Possible causes include cancellation, explicit invocation of completeExceptionally, and abrupt termination of a CompletionStage action.
You can also add exceptional block for the completableFuture, so while executing task if any exception occurs it will execute the exceptionally with exception an input argument
CompletableFuture<String> future = CompletableFuture.supplyAsync(()-> "Success")
.exceptionally(ex->"failed");
In the above example if any exception occurs executing supplyAsync failed will return or else Success is returned
Got it, by calling the following code, it will solve my problem
try {
response.join();
}
catch(CompletionException ex) {
try {
throw ex.getCause();
}
catch(Throwable impossible) {
throw impossible;
}
}

How to create Observable out of Runnable?

Sometimes I want to trigger a Runnable as part of my Observable sequence, but the Runnable does not report progress.
I have written a simple factory for wrapping a Runnable object into an Observable:
public static <T> Observable<T> fromRunnable(final Runnable action) {
if (action == null) {
throw new NullPointerException("action");
}
return Observable.fromPublisher(subscriber -> {
try {
action.run();
subscriber.onComplete();
} catch (final Throwable throwable) {
subscriber.onError(throwable);
}
});
}
Usage:
Observable.concat(
someTask,
MoreObservables.fromRunnable(() -> {
System.out.println("Done. ");
}));
But does RxJava 2 provide this functionality already?
There is no such factory method for Observable, but Completable could be made from Runnable. So you could create a Completable first and then convert it to Observable:
Observable.concat(
someTask,
Completable.fromRunnable(() -> {
System.out.println("Done");
}).toObservable()
);
Update: Dealing with exceptions
Completable.fromRunnable internally catches exceptions from its Runnable and pushes them into the stream as onError emissions. However, if you are using Java, you have to deal with checked exceptions inside the run() method by yourself. To avoid that you could utilize Callable instead of Runnable, since its call() method's signature declares that it can throw exceptions. Completable.fromCallable() wraps exceptions into onError emissions as well:
Observable.concat(
someTask,
Completable.fromCallable(() -> {
System.out.println("Done");
return null;
}).toObservable()
);
Also Callable could be used to create an Observable or Single with a single item emission.
P.S. Check out the source code, these methods are pretty straightforward.
P.P.S. Kotlin has no checked exceptions ;)
Update 2
There is also fromAction factory method for creating Completable. It accepts Action objects.
A functional interface similar to Runnable but allows throwing a checked exception.
So the code could be simplified to:
Observable.concat(
someTask,
Completable.fromAction(() -> {
System.out.println("Done");
}).toObservable()
);

How is exception handling done in a Callable

I understand that callable's call can throw the exception to the parent method calling it which is not the case with runnable.
I wonder how because it's a thread method and is the bottommost method of the thread stack.
The point of Callable is to have your exception thrown to your calling thread, for example when you get the result of a Future to which you submitted your callable.
public class CallableClass implements Callable<String> {
...
}
ExecutorService executor = new ScheduledThreadPoolExecutor(5);
Future<Integer> future = executor.submit(callable);
try {
System.out.println(future.get());
} catch (Exception e) {
// do something
}
Callable.call() can't be the bottommost stack frame. It's always called by another method that will then catch the exception. Callable should usually be used to asynchronously compute values and later get them with a Future object. The operation might throw an exception that is later rethrown when you try to get the Future's value.
Runnable is simply supposed to run an operation that doesn't return anything. All exception handling should be done within the Runnable because it's unclear how any exceptions thrown in Runnable.run() should be handled. (The exception from a Callable is usually returned to the caller with the Future)

java concurrent Future task returning null in case of any exception and not propagating it

I am new to java.util.concurrent package and wrote a simple method which fetches some rows from DB. I made sure that my DB call throws back an exception to handle it. But i am not seeing the exception propagating back to me. Instead call to my method is returning null.
Can some one help me in this case? Here is my sample method call
private FutureTask<List<ConditionFact>> getConditionFacts(final Member member) throws Exception {
FutureTask<List<ConditionFact>> task = new FutureTask<List<ConditionFact>>(new Callable<List<ConditionFact>>() {
public List<ConditionFact> call() throws Exception {
return saeFactDao.findConditionFactsByMember(member);
}
});
taskExecutor.execute(task);
return task;
}
I googled and found some pages around it. But don't see any concrete solutions for it. Experts please help....
The taskExecutor is object of org.springframework.core.task.TaskExecutor
The FutureTask will execute in a new thread and, if an exception occurs, will store it in an instance field. It's only when you'll ask the result of the execution that you will get the exception, wrapped inside an ExecutionException:
FutureTask<List<ConditionFact>> task = getConditionFacts(member);
// wait for the task to complete and get the result:
try {
List<ConditionFact> conditionFacts = task.get();
}
catch (ExecutionException e) {
// an exception occurred.
Throwable cause = e.getCause(); // cause is the original exception thrown by the DAO
}

Categories

Resources