仅在达到条件时才链接多个CompletionStage

Pel*_*cho 15 java-8 completable-future

我有几种CompletionStage方法可以链接.问题是第一个的结果将决定是否应该执行下一个.现在,实现这一目标的唯一方法似乎是将"特殊"参数传递给next,CompletionStage因此它不会执行完整的代码.例如:

public enum SomeResult {
    RESULT_1,
    RESULT_2,
    RESULT_3
}

public CompletionStage<SomeResult> someMethod(SomeArgument someArgument) {

    return CompletableFuture.supplyAsync(() -> {
        // loooooong operation
        if (someCondition)
            return validValue;
        else
            return null;
    }).thenCompose(result -> {
        if (result != null)
            return someMethodThatReturnsACompletionStage(result);
        else
            return CompletableFuture.completedFuture(null);
    }).thenApply(result -> {
        if (result == null)
            return ChainingResult.RESULT_1;
        else if (result.someCondition())
            return ChainingResult.RESULT_2;
        else
            return ChainingResult.RESULT_3;
    });
}
Run Code Online (Sandbox Code Playgroud)

因为整个代码依赖于第一个代码someCondition(如果它是false结果将是RESULT_1,如果不是那么整个代码应该被执行)这个结构对我来说看起来有点难看.有没有办法决定是否应该执行2nd(thenCompose(...))和3rd(thenApply(...))方法?

Hol*_*ger 13

你可以这样做:

public CompletionStage<SomeResult> someMethod(SomeArgument someArgument) {
    CompletableFuture<SomeResult> shortCut = new CompletableFuture<>();
    CompletableFuture<ResultOfFirstOp> withChain = new CompletableFuture<>();

    CompletableFuture.runAsync(() -> {
        // loooooong operation
        if (someCondition)
            withChain.complete(validValue);
        else
            shortCut.complete(SomeResult.RESULT_1);
    });
    return withChain
        .thenCompose(result -> someMethodThatReturnsACompletionStage(result))
        .thenApply(result ->
                   result.someCondition()? SomeResult.RESULT_2: SomeResult.RESULT_3)
        .applyToEither(shortCut, Function.identity());
}
Run Code Online (Sandbox Code Playgroud)

而不是CompletableFuture我们创建两个,代表我们可能采取的不同执行路径.loooooong操作以runnable的形式提交,然后故意完成其中一个操作CompletableFuture.后续阶段链接到表示已满足条件的阶段,然后两个执行路径在最后applyToEither(shortCut, Function.identity())一步连接.

shortCut未来已经最终结果的类型,并将与完成RESULT_1,你的结果null传递路径,这将导致整个操作的即时完成.如果您不喜欢第一阶段与快捷方式的实际结果值之间的依赖关系,您可以像这样收回它:

public CompletionStage<SomeResult> someMethod(SomeArgument someArgument) {
    CompletableFuture<Object> shortCut = new CompletableFuture<>();
    CompletableFuture<ResultOfFirstOp> withChain = new CompletableFuture<>();

    CompletableFuture.runAsync(() -> {
        // loooooong operation
        if (someCondition)
            withChain.complete(validValue);
        else
            shortCut.complete(null);
    });
    return withChain
        .thenCompose(result -> someMethodThatReturnsACompletionStage(result))
        .thenApply(result ->
                   result.someCondition()? SomeResult.RESULT_2: SomeResult.RESULT_3)
        .applyToEither(shortCut.thenApply(x -> SomeResult.RESULT_1), Function.identity());
}
Run Code Online (Sandbox Code Playgroud)

如果您的第三步不是示例性的,但看起来与问题中显示的完全相同,则可以将其与代码路径连接步骤合并:

public CompletionStage<SomeResult> someMethod(SomeArgument someArgument) {
    CompletableFuture<ResultOfSecondOp> shortCut = new CompletableFuture<>();
    CompletableFuture<ResultOfFirstOp> withChain = new CompletableFuture<>();

    CompletableFuture.runAsync(() -> {
        // loooooong operation
        if (someCondition)
            withChain.complete(validValue);
        else
            shortCut.complete(null);
    });
    return withChain
        .thenCompose(result -> someMethodThatReturnsACompletionStage(result))
        .applyToEither(shortCut, result -> result==null? SomeResult.RESULT_1:
            result.someCondition()? SomeResult.RESULT_2: SomeResult.RESULT_3);
}
Run Code Online (Sandbox Code Playgroud)

然后我们只跳过第二步,即someMethodThatReturnsACompletionStage调用,但是仍然可以代表一长串中间步骤,所有步骤都跳过,而不需要通过nullcheck推出手动跳过.