【问题标题】:Stop CompletableFuture chaining inside the Supplier停止供应商内部的 CompletableFuture 链接
【发布时间】:2020-01-02 06:59:49
【问题描述】:
我有这样的操作,
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;
});
}
在第一个块中,我检查了一些条件(i == 5),如果它是真的,我不需要其余的操作。我不想抛出异常来取消其余的,因为这不是特殊情况。除了将一些布尔值传递给每个操作之外,还有什么好方法吗?
【问题讨论】:
标签:
java
asynchronous
java-8
java-stream
completable-future
【解决方案1】:
CompletableFuture 没有支持条件语句的机制。在您的情况下,可以通过将i != 5 的所有任务提取到一个CompletableFuture 和thenCompose 中来简化代码。
其他解决方法是创建一个地图,对其进行过滤并使用它创建一个可完成的未来:
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);
在这里我正在创建一个地图Predicate -> Runnable。然后我过滤掉所有不满足谓词的对,并将可运行对象包装到CompletableFutures 中。最后composed 是一个CompletableFuture,它由所有所需的可运行文件组成。
【解决方案2】:
CompletableFuture.thenCompose() 应该可以解决问题。
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;
});
}
}