How to convert the code to use CompletableFuture? - java

I used to have a callable class
class SampleTask implements Callable<Double> {
#Override
public Double call() throws Exception {
return 0d;
}
}
I used to use ExecutorService to submit the Callable. How to change to use CompletableFuture.supplyAsync?
The following code cannot compile
SampleTask task = new SampleTask();
CompletableFuture.supplyAsync(task);
No instance of type of variable U exists so that SampleTask conforms to Supplier

For your callable as written, you could simply use CompletableFuture.supplyAsync(() -> 0d);.
If, however, you have an existing Callable, using it with CompletableFuture is not so straight-forward due to the checked exceptions that a callable might throw.
You may use an ad-hoc Supplier which catches exceptions and re-throws it wrapped in an unchecked exception like
CompletableFuture.supplyAsync(() -> {
try { return callable.call(); }
catch(Exception e) { throw new CompletionException(e); }
})
Using the specific type CompletionException instead of an arbitrary subtype of RuntimeException avoids getting a CompletionException wrapping a runtime exception wrapping the actual exception when calling join().
Still, you’ll notice the wrapping when chaining an exception handler to the CompletableFuture. Also, the CompletionException thrown by join() will be the one created in the catch clause, hence contain the stack trace of some background thread rather than the thread calling join(). In other words, the behavior still differs from a Supplier that throws an exception.
Using the slightly more complicated
public static <R> CompletableFuture<R> callAsync(Callable<R> callable) {
CompletableFuture<R> cf = new CompletableFuture<>();
CompletableFuture.runAsync(() -> {
try { cf.complete(callable.call()); }
catch(Throwable ex) { cf.completeExceptionally(ex); }
});
return cf;
}
you get a CompletableFuture which behaves exactly like supplyAsync, without additional wrapper exception types, i.e. if you use
callAsync(task).exceptionally(t -> {
t.printStackTrace();
return 42.0;
})
t will be the exact exception thrown by the Callable, if any, even if it is a checked exception. Also callAsync(task).join() would produce a CompletionException with a stack trace of the caller of join() directly wrapping the exception thrown by the Callable in the exceptional case, exactly like with the Supplier or like with runAsync.

supplyAsync() expects a Supplier<U> and you are giving it a Callable.
The error message is telling you that the compiler has tried to find a type to use for U such that your SampleTask "is a" Supplier<U>, but it can't find one.
Java will implicitly "promote" a lambda to a functional interface such as Callable or Supplier. But it won't treat functional interfaces as interchangeable -- that is, you can't use a Callable where a Supplier is expected.
You can make a suitable lambda in-place:
SimpleTask task = new SimpleTask();
CompletableFuture.supplyAsync(() -> task.call());
Note that this works if SimpleTask's call() is:
public Double call() { // note no exception declared
return 0d;
}
The fact that SimpleTask happens to implement Callable is not relevant to the code above.
If you want this to work with an arbitrary Callable, or if you declare task as a Callable:
Callable callable = new SimpleTask();
CompletableFuture.supplyAsync(() -> callable.call());
... then you will get a compiler error about the uncaught exception. Your lambda will need to catch the exception and handle it (perhaps rethrowing as an unchecked exception, as described in other answers).
Or you could make SampleTask implement Supplier<Double>.
Part of the motivation for lambdas is that writing things like Callable was too verbose. So you might well leave out the intermediate class and go directly for:
CompleteableFuture<Double> future = CompletableFuture.supplyAsync(() -> 0d);
This applies for more complicated suppliers too:
CompleteableFuture<Double> future = CompletableFuture.supplyAsync(() -> {
Foo foo = slowQuery();
return transformToDouble(foo);
});

Since CompleteableFuture::supplyAsync expects a Supplier<Double> and not Callable<Double> you should go with:
Callable<Double> task = new SampleTask();
CompletableFuture.supplyAsync(() -> {
try {
return task.call();
} catch (Exception e) {
throw new RuntimeException(e);
}
});

I had this come up recently and used Vavr to solve it (was already using it for other things, too), and it worked out great for me:
CompletableFuture.supplyAsync( () -> Try.ofCallable( callable ).get() )
Or to get a Supplier of that CompletableFuture:
() -> CompletableFuture.supplyAsync( () -> Try.ofCallable( callable ).get() )
In all cases I tested this returned exactly and threw exactly what the callable itself did.

Related

Catch and throw custom Exception from Java ExecutorService

I have a function that goes through a list of HappyObjects and sets their fields asynchronously. In the Callable, a JsonProcessingException can occur. I have to wrap this and other exceptions from this function into a custom exception (ControllerException) and throw that instead.
Other Stack Overflow posts seem to suggest collect into a List of Futures and use get() to catch the exceptions. Thus, this is what I have so far:
default List<HappyObj> fillfunction(final List<HappyObj> happyObjs) throws ControllerException {
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newCachedThreadPool();
List<Future<HappyObj>> futures = new ArrayList<>();
for (HappyObj happyObj : happyObjs) {
Future<HappyObj> future = executor.submit(
() -> {
final List<Mood> moods = getMoods();
for (Mood mood : moods) {
final String json = getJsonEmotion();
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
List<Emotion> emotions =
mapper.readValue(json, new TypeReference<List<Emotion>>() {}); //JsonProcessingException can occur here
MoodMetadata metadata = mood.getMoodMetadata();
if (metadata != null && metadata.getEmotionMetadata() != null) {
metadata.getEmotionMetadata().setEmotions(emotions);
}
}
happyObj.setMoods(moods);
return happyObj;
});
futures.add(future);
}
executor.shutdown();
final long maxSlaSec = 1;
try {
executor.awaitTermination(maxSlaSec, TimeUnit.SECONDS);
List<HappyObj> happyResult = new ArrayList<>();
for (Future<HappyObj> future : futures) {
happyResult.add(future.get());
}
return happyResult;
} catch (InterruptedException | ExecutionException e) {
executor.shutdownNow();
throw new ControllerException(e);
}
}
Is there a more elegant way than iterating through List<Future> and calling get on each to catch ExecutorException? I thought about using execute() vs. submit(), but then I can't handle the JsonProcessingException. I saw another post suggesting creating a ThreadPoolExecutor subclass and override the afterExecute(), but I wasn't able to handle the JsonProcessingException.
One of the reasons I asked this question is because since this method consists mainly of setters, the function was originally manipulating the given objects and returning void.
According to the docs of ExecutionException (and also the docs of Future#get), it already has wrapped that information. That is, you can use its getCause to inspect the Exception thrown by the Callable's body.
Notice that Callable#call itself throws an Exception... When you throw an Exception from the Callable, it will be wrapped into an ExecutionException which will be thrown from the Future#get method, for each Callable, meaning that you can change your loop to catch an ExecutionException for each Future and inspect its getCause!
So you don't actually need to wrap it to a custom ControllerException.
The Callables you create, can still return null of type Void for example, without needing to do anything about them.
Unless the scenario changes, then you don't need to extend ThreadPoolExecutor in this case. You don't even have to cast to ThreadPoolExecutor, because the ExecutorService interface already has the submits you need. Just throw whatever Exception you need from the Callable (such as JsonProcessingException that you mentioned) when something goes wrong in the Callable, and then inspect the ExecutionException from each Future#get method to tell if an JsonProcessingException was thrown (and you can also determine in which one it was thrown, if you need).
Is there a more elegant way than iterating through List and calling get on each to catch ExecutorException?
In my opinion, no, there is not, because you want to submit all Callables first, then let them run in parallel, and at the end inspect their ExecutionException for any Exception thrown by the Callables' body for each Callable (via Future#get of the returned Future by submit).

How to know if a Future is created with Callable or Runnable

I am dipping my feet in Futures. A Future can be created with a Runnable and with a Callable. Is there a way to decide how it was created?
For example, I have the following code:
Future<?> future = null;
Future<?> future2 = null;
ExecutorService service = null;
service = Executors.newSingleThreadExecutor();
future = service.submit(() -> {
for (int i = 0; i < 5; ++i) {
System.out.println("Printing record: " + i);
Thread.sleep(5);
}
return "Done";
});
future2 = service.submit(() -> System.out.println("Printing zoo inventory"));
System.out.println("================================================================");
System.out.println(future);
System.out.println(future.get().getClass());
System.out.println(future.get());
System.out.println("================================================================");
System.out.println(future2);
try {
System.out.println(future2.get().getClass());
System.out.println(future2.get());
} catch (ExecutionException e) {
System.out.println("Could not do a get");
}
System.out.println("================================================================");
This results in ending with:
================================================================
java.util.concurrent.FutureTask#5caf905d[Completed normally]
class java.lang.String
Done
================================================================
java.util.concurrent.FutureTask#1f32e575[Completed normally]
Exception in thread "main" java.lang.NullPointerException
at ZooInfo.main(ZooInfo.java:56)
I could solve this by using:
if (future2.get() == null) {
System.out.println("Made with a Runnable");
} else {
System.out.println(future2.get().getClass());
System.out.println(future2.get());
}
The problem with this is that when the Runnable still takes some time, I am waiting on the get for nothing. Is there a way to determine if a Future was created with a Runnable, or a Callable without resorting to using get()?
I don't believe that you really need to know whether the Future was created from a Runnable or a Callable.
For one thing, there are more ways than that to create a Future: for example, CompleteableFuture is not created from either; and, more generally, since Future is an interface, one can create instances however you like.
For another: the abstraction of Future is that it is something that gives you a (possibly null) value when it completes, or throws an exception. That's all it is meant to do.
(Also, your current approach of checking for nullity of the return value doesn't work reliably because Callable.call() is allowed to return null).
If you need it to do something else, you may want to revisit your design so you can simply treat it as it is intended.
But if you really do have a use case that does require you to know how it was created, you need to control the creation. Rather than letting callers submit code directly to the executor, wrap in a class like this:
class YourExecutor {
// Initialize in ctor.
private final ExecutorService executor;
FromRunnable submit(Runnable r) {
return new FromRunnable(executor.submit(r));
}
<T> FromCallable<T> submit(Callable<? extends T> c) {
return new FromCallable<>(executor.submit(c));
}
}
where FromRunnable and FromCallable<T> are classes implementing Future<Void> and Future<T> respectively, which delegate all of the methods to another instance of a compatible Future (passed as the constructor parameter).
You can then check the provenance using instanceof; or by some other means, such as extending a common base case or interface which provides a method describing the provenance.
But, just to reiterate, a better approach is to design your code so it doesn't need to know.

Why can't checked exceptions in a java stream be thrown at method level?

I've been learning about concurrency and the streams API and came across this. The offerLast()method can throw InterruptedException, so I get that I must handle it. What I don't get is why can't I throw it at the method level by adding throws Exception?. As it is this code does not compile.
static BlockingDeque<Integer> queue = new LinkedBlockingDeque<>();
public static void testing() throws Exception {
IntStream.iterate(1, i -> i+1).limit(5)
.parallel()
.forEach(s -> queue.offerLast(s, 10000, TimeUnit.MILLISECONDS));
}
I know it can be solved by surrounding it in a try/catch, or by creating a wrapper method that handles the error, but I'm still trying to understand why it can't be thrown at the method level.
Because lambda expressions are not always evaluated immediately.
Let's you have this:
public Supplier<String> giveMeASupplier() throws Exception {
return () -> someMethodThatThrowsCheckedException()
}
According to you, the above would work. Right?
Now in another method, I can do this:
Suppler<String> supplier = null;
try {
supplier = giveMeASupplier() // no exception is thrown here.
} catch (Exception ex) {
ex.printStackTrace();
}
if (supplier != null) {
System.out.println(supplier.get()); // this might throw an exception! Yet it's not in a try...catch!
}
Now what do you think would happen if supplier.get() throws an exception? Is there anything to catch it? No. If somehow the catch block a few lines before gets run, then it would be really weird.
The simple answer is that the "method" you're referring to is Consumer.accept, not YourClass.testing.
The lambda s -> queue.offerLast(s, 10000, TimeUnit.MILLISECONDS) is an implementation of java.util.function.Consumer.accept(T), which doesn't declare that it can throw InterruptedException.
And this behavior is not particular to streams, wherever a lambda expression is defined, it must comply with the signature of the abstract method of the functional interface it implements.

Using Java `CompletablyFuture.exceptionally` to optionally continue through exceptions

I have a series of asynchronous tasks chained together using Java CompletableFutures. The code looks something like this:
CompletableFuture<Result> doTasks(final TaskId id) {
return firstTask.workAsync(id)
.thenComposeAsync(__ -> secondTask.workAsync(id))
.thenComposeAsync(__ -> thirdTask.workAsync(id))
.thenApplyAsync(__ -> fourthTask.workAsync(id));
}
However, firstTask.workAsync throws an exception indicating that the work has already been completed, which is OK in this situation, so I would like to just ignore it and continue through the chain.
Of course, I could just wrap that bit in a separate function where I can handle the exception, but is there a way to handle it directly in the CompletableFuture chain and continue to throw all other exceptions?
A co-worker suggested I use CompletableFuture.exceptionally, but all of the examples online that I see are totally useless and just return null, which looks like it would kill the chain. How would I use that in this case?
CompletableFuture.exceptionally can be used to continue when getting an exception in a CompletableFuture. In a nutshell, you need to check the type of the exception, and if it's an exception you want to continue on, you can return a new CompletableFuture, which can be empty since the result is not used down the chain.
CompletableFuture<Result> doTasks(final TaskId id) {
return firstTask.workAsync(id)
.exceptionally(t -> {
// Will continue down the chain if matches
if (t instanceof TotallyOkException) {
return null;
}
// This will throw an ExecutionException. I convert it to a RuntimeException here
// because I don't want to add throws statements up the chain.
throw new RuntimeException(t);
})
.thenComposeAsync(__ -> secondTask.workAsync(id))
.thenComposeAsync(__ -> thirdTask.workAsync(id))
.thenApplyAsync(__ -> fourthTask.workAsync(id));
}
In this case, it will throw all non-TotallyOkException exceptions.
Returning null in your exceptionally function will not, in itself, kill the chain. The only way it will kill the chain is a result of lack of null handling in the downstream function and causing a NullPointerException.
Your exceptionally function can be set up to handle some types of exception and not others. For example:
return firstTask.workAsync(id)
.thenComposeAsync(firstResult -> secondTask.workAsync(id))
.exceptionally(t -> {
if (t instanceof TransientException) {
return getUsingBackupMethod(id);
}
throw new RuntimeException(t);
});
This exceptionally function will (effectively) catch an exception thrown from either of the first two tasks.

When should prefer Callable over Runnable and why?

On SO, I found all theoretical difference between Callable and Runnable and all are almost similar. But, I didn't understand why was Callable introduced in later version ? What was the gap/flaws in Runnable, which Callable is capable of doing ? Anyone can explain with scenario where Callable is only solution ?
Callable has two differences. It can return a value or throw a checked exception.
This make a difference when using lambdas so that even though you don't specify which one to sue the compiler has to work it out.
// the lambda here must be a Callable as it returns an Integer
int result = executor.submit(() -> return 2);
// the lambda here must be a Runnable as it returns nothing
executors.submit(() -> System.out.println("Hello World"));
// the lambda here must be a Callable as an exception could be thrown
executor.submit(() -> {
try (FileWriter out = new FileWriter("out.txt")) {
out.write("Hello World\n");
}
return null; // Callable has to return something
});
Well, the documentation does answer a big part of your question:
The Callable interface is similar to Runnable, in that both are
designed for classes whose instances are potentially executed by
another thread. A Runnable, however, does not return a result and
cannot throw a checked exception.
So, you are jusing Callable instead of Runnable, if...
You need to throw a checked exception or...
You need to return an object (of course you could simulate this by giving your runnable an internal result object, etc. - but it's easier that way)
For example...
ExecutorService service = ... some ExecutorService...;
Callable<Integer> myCallable = new MyCallable( ... some parameters ... );
Future<Integer> future = service.submit( myCallable );
...
Integer myResult = future.get(); // will wait and return return value from callable as soon as done

Categories

Resources