基于条件的可完成未来捷径链

use*_*281 3 java-8 completable-future

我想根据特定条件跳过可完成的功能链。我尝试了在多个完成阶段进行链接时提出的解决方案,但似乎没有用。这里的代码:

@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());
    }
} 
Run Code Online (Sandbox Code Playgroud)

输出:

Completing result1. Result: false
Completing result2. Result: true
Completing result3. Result: true
Run Code Online (Sandbox Code Playgroud)

即使“结果”可完成期货被标记为已完成,后续的可完成期货仍将执行。如何跳过Completablefuture 2和3?

Hol*_*ger 5

您已经创建了一个依赖链,如下所示:

  first
    ?  (?)
   next  result
    ?  ?
  final
Run Code Online (Sandbox Code Playgroud)

(?)是显式调用完成result.complete(…),但所有其他的完成自动发生。final通过via创建的阶段applyToEither将使用任何一个先决条件完成,以先完成者为准,但不会修改它们的行为。

原则上,任何代码可以调用complete它,而不会影响这些阶段是任可能完成final,否则阶段。取消同样适用。调用cancel一个阶段将完成该阶段,然后调用该方法,而不会影响用于构造该阶段的阶段。

所链接问题的答案会产生以下阶段

    first
   (?)  (?)
 next 1  result
   ?     |
 next 2  |
   ?    ?
    final
Run Code Online (Sandbox Code Playgroud)

关键是,初始阶段将CompletableFuture显式完成两个中的任何一个,而不触发自动完成。依赖阶段的其他链条将永远不会得到评估。由于final阶段是applyToEither,因此只有一条链的完成足以评估最终功能。它仍然不会影响先决条件阶段。

请注意thenCompose,由于函数仍会返回,因此对于由操作组成的链,可以以更简单的方式实现类似的逻辑CompletableFuture。因此,只需返回一个新CompletableFuture快捷键即可解决此问题,而该快捷键在您想要快捷方式时将永远不会完成。您甚至可以重写您的姓名首字母runAsyncthenCompose代替使用:

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();
}
Run Code Online (Sandbox Code Playgroud)
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();
}
Run Code Online (Sandbox Code Playgroud)