仅在达到条件时才链接多个CompletionStage [英] Chaining several CompletionStage only if a condition is achieved

查看:320
本文介绍了仅在达到条件时才链接多个CompletionStage的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have several CompletionStage methods that I'd like to chain. The problem is that the result of the first one will determine if the next ones should be executed. Right now the only way to achieve this seems to be passing "special" arguments to next CompletionStage so it doesn't execute the full code. For example:

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;
    });
}

由于整个代码取决于第一个 someCondition (如果它是 false 那么结果将是 RESULT_1 ,如果没有那么整个代码应该是被执行)这个结构对我来说有点难看。有没有办法决定第二个( thenCompose(...))和第三个( thenApply(...))方法应该执行?

Since the whole code depends on the first someCondition (if it's false then the result will be RESULT_1, if not then the whole code should be executed) this construction looks a bit ugly to me. Is there any way to decide if 2nd (thenCompose(...)) and 3rd (thenApply(...)) methods should be executed?

推荐答案

你可以这样做:

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());
}

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

Instead of one CompletableFuture we create two, representing the different execution paths we might take. The loooooong operation is submitted as runnable then and will deliberately complete one of these CompletableFuture. The followup stages are chained to the stage representing the fulfilled condition, then both execution paths join at the last applyToEither(shortCut, Function.identity()) step.

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

The shortCut future has already the type of the final result and will be completed with the RESULT_1, the result of your nullpassing path, which will cause the immediate completion of the entire operation. If you don’t like the dependency between the first stage and the actual result value of the short-cut, you can retract it like this:

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());
}

如果您的第三步不是典范,但看起来与问题中显示的完全一致,您可以将其与代码路径合并步骤合并:

If your third step wasn’t exemplary but looks exactly like shown in the question, you could merge it with the code path joining step:

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);
}

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

then we only skip the second step, the someMethodThatReturnsACompletionStage invocation, but that can still stand for a long chain of intermediate steps, all skipped without the need to roll out a manual skipping via nullcheck.

这篇关于仅在达到条件时才链接多个CompletionStage的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆