我想根据特定条件跳过可完成的 future 链。我尝试了 chaining several completionstage 中提出的解决方案,但似乎不起作用。这是代码:
@RunWith(JUnit4.class)
public class ExceptionHandlingTests {
@Test
public void test1() {
CompletableFuture<Integer> result = new CompletableFuture<>();
CompletableFuture.runAsync(() -> {
System.out.println("Completing result1. Result: " + result.isDone());
result.complete(10);
}).thenCompose(x -> {
System.out.println("Completing result2. Result: " + result.isDone());
result.complete(10);
return CompletableFuture.completedFuture(5);
}).thenCompose(x -> {
System.out.println("Completing result3. Result: " + result.isDone());
result.complete(10);
return CompletableFuture.completedFuture(5);
}).applyToEither(result, Function.identity());
}
}
输出:
Completing result1. Result: false
Completing result2. Result: true
Completing result3. Result: true
即使“结果”completablefuture 被标记为已完成,后续的 completablefuture 仍会执行。如何跳过Completablefuture 2和3?
最佳答案
您已经创建了这样的依赖链:
first
↓ (↘)
next result
↓ ↙
final
(↘)
是显式完成调用 result.complete(…)
,但所有其他完成都会自动发生。通过 applyToEither
创建的 final
阶段将在满足任一先决条件(以先完成者为准)的情况下完成,但不会修改它们的行为。
原则上,任何代码都可以在其上调用complete
,而不会影响这些阶段中的任何一个,否则可能完成final
阶段。这同样适用于取消。在阶段上调用 cancel
将完成该阶段以及您调用的方法,而不会影响您用于构造该阶段的阶段。
链接问题的答案会创建类似的阶段
first
(↙) (↘)
next 1 result
↓ |
next 2 |
↘ ↙
final
关键点是,初始阶段将显式完成两个 CompletableFuture
中的一个,而不触发自动完成。其他依赖阶段链永远不会被评估。由于final
阶段是一个applyToEither
,因此仅完成一个链就足以评估最终函数。它仍然不影响先决条件阶段。
请注意,对于由 thenCompose
操作组成的链,您可以以更简单的方式实现类似的逻辑,因为您的函数无论如何都会返回 CompletableFuture
。因此,只需返回一个新的 CompletableFuture
,当您想要快捷方式时,它永远不会完成,就可以解决问题。您甚至可以重写最初的 runAsync
以使用 thenCompose
代替:
for(int shortCutAt: IntStream.range(0, 4).toArray()) {
System.out.println("Example execution with "
+(shortCutAt==0? "no shortcut": "shortcut at "+shortCutAt));
CompletableFuture<Integer> result = new CompletableFuture<>();
CompletableFuture.completedFuture(null).thenCompose(justVoid -> { // runAsync
System.out.println("Completing result1. Result: " + result.isDone());
if(shortCutAt == 1) { result.complete(10); return new CompletableFuture<>(); }
return CompletableFuture.completedFuture(justVoid);
}).thenCompose(x -> {
System.out.println("Completing result2. Result: " + result.isDone());
if(shortCutAt == 2) { result.complete(10); return new CompletableFuture<>(); }
return CompletableFuture.completedFuture(5);
}).thenCompose(x -> {
System.out.println("Completing result3. Result: " + result.isDone());
if(shortCutAt == 3) { result.complete(10); return new CompletableFuture<>(); }
return CompletableFuture.completedFuture(5);
})
.applyToEither(result, Function.identity())
.thenAccept(fr -> System.out.println("final result: "+fr));
System.out.println();
}
Example execution with no shortcut
Completing result1. Result: false
Completing result2. Result: false
Completing result3. Result: false
final result: 5
Example execution with shortcut at 1
Completing result1. Result: false
final result: 10
Example execution with shortcut at 2
Completing result1. Result: false
Completing result2. Result: false
final result: 10
Example execution with shortcut at 3
Completing result1. Result: false
Completing result2. Result: false
Completing result3. Result: false
final result: 10
关于java-8 - 基于条件的CompletableFuture的捷径链,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48145264/