java-8 - 基于条件的CompletableFuture的捷径链

标签 java-8 completable-future

我想根据特定条件跳过可完成的 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/

相关文章:

java - 使用可完成 future 的实体的流程列表

java - 处理多个异步操作并处理每个异步操作以进行进一步处理的最佳方法是什么?

java - 直接从 CompletableFuture.thenAccept 返回值

java - CompletableFuture#whenComplete 如果使用 thenApply 则不调用

java-8 - Java8 谓词与 try catch

java - 原始值的映射替代

java - 从java 8流中获取N(3)个列表(基于ENUM性别(男,女,其他))并基于ENUM过滤条件

java - 当每个对象可以分为多个组时如何对对象进行分组?

java - 从 Oracle JDK 迁移到 OpenJDK 所需的更改

Kotlin supplyAsync with executor