我想根据具体情况跳过完整的未完成链接链。我尝试了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
即使&#34;结果&#34; completablefuture已标记完成,后续的可完成期限仍在执行中。如何跳过Completablefuture 2和3?
答案 0 :(得分:4)
您已经创建了这样的依赖关系链:
first
↓ (↘)
next result
↓ ↙
final
(↘)
是显式完成调用result.complete(…)
,但所有其他完成都会自动发生。通过final
创建的applyToEither
阶段将使用任一先决条件完成,以先完成为准,但不会修改它们的行为。
原则上,任何代码都可以在其上调用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