I have such an operation,
public void createFuture() {
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 5);
future.thenApply(i -> {
if (i == 5) {
System.out.println("hello, i equals to 5 so expensive operations are unnecessary");
}
return i;
}).thenApply(i -> {
if (i != 5) {
System.out.println("Expensive operation");
}
return i;
}).thenApply(i -> {
if (i != 5) {
System.out.println("Expensive operation");
}
return i;
}).thenApply(i -> {
if (i != 5) {
System.out.println("Expensive operation");
}
return i;
}).thenApply(i -> {
if (i != 5) {
System.out.println("Expensive operation");
}
return i;
});
}
Here in the first block, I check some condition (i == 5) and if it is true, I don't need the rest of the operations. I don't want to throw an exception to cancel the rest because this is not an exceptional situation. Is there a nice way to do it other than passing some boolean to each operation?
CompletableFuture.thenCompose() should do the trick.
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ExecutionException;
class Scratch {
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 5);
CompletableFuture<Integer> composed = future.thenCompose(number -> {
if (number == 5)
return simpleFuture(number);
else
return complexFuture(number);
});
System.out.println(composed.get());
}
private static CompletionStage<Integer> complexFuture(Integer number) {
return CompletableFuture.completedFuture(number)
.thenApply(i -> {
System.out.println("I am expensive");
return i;
});
}
private static CompletableFuture<Integer> simpleFuture(Integer number) {
return CompletableFuture.completedFuture(number)
.thenApply(i -> {
System.out.println("I am cheap");
return i;
});
}
}
CompletableFuture does not have mechanisms to support conditional statements. In your case the code can be simplified by extracting all tasks for i != 5 into one CompletableFuture with thenCompose.
Other workaround would be to create a map, filter it and create a completable future with it:
Map<Predicate<Integer>, Runnable> m = Map.of(
integer -> integer == 5,
() -> System.out.println("Task 1"),
integer -> integer != 5,
() -> System.out.println("Task 2"),
integer -> integer != 5,
() -> System.out.println("Task 3")
);
CompletableFuture[] runnables = m.entrySet().stream()
.filter(e -> e.getKey().test(5))
.map(Map.Entry::getValue)
.map(CompletableFuture::runAsync)
.toArray(CompletableFuture[]::new);
CompletableFuture composed = CompletableFuture.allOf(runnables);
Here I'm creating a map Predicate -> Runnable. Then I'm filtering out all pairs that do not fulfill the predicate and wrapping runnables into CompletableFutures. At the end composed is a CompletableFuture, that is composed of all the desired runnables.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With