Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/wcf/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 8 仅当达到某个条件时才链接多个CompletionStage_Java 8_Completable Future - Fatal编程技术网

Java 8 仅当达到某个条件时才链接多个CompletionStage

Java 8 仅当达到某个条件时才链接多个CompletionStage,java-8,completable-future,Java 8,Completable Future,我有几个CompletionStage方法要链接。问题是,第一个的结果将决定是否应该执行下一个。现在实现这一点的唯一方法似乎是将“特殊”参数传递给下一个CompletionStage,这样它就不会执行完整的代码。例如: public enum SomeResult { RESULT_1, RESULT_2, RESULT_3 } public CompletionStage<SomeResult> someMethod(SomeArgument someAr

我有几个
CompletionStage
方法要链接。问题是,第一个的结果将决定是否应该执行下一个。现在实现这一点的唯一方法似乎是将“特殊”参数传递给下一个
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;
    });
}
公共枚举结果{
结果1,
结果2,
结果3
}
公共CompletionStage someMethod(SomeArgument SomeArgument){
返回CompletableFuture.SupplySync(()->{
//Looooong手术
如果(某些条件)
返回有效值;
其他的
返回null;
}).然后撰写(结果->{
如果(结果!=null)
返回返回CompletionStage(结果)的方法;
其他的
返回CompletableFuture.completedFuture(空);
})。然后应用(结果->{
如果(结果==null)
返回ChainingResult.RESULT_1;
else if(result.someCondition())
返回chainResult.RESULT_2;
其他的
返回chainResult.RESULT_3;
});
}

由于整个代码依赖于第一个
someCondition
(如果它是
false
,则结果将是
result\u 1
,如果不是,则应执行整个代码),因此这种构造在我看来有点难看。有没有办法决定是否应该执行第二个(
然后组合(…)
)和第三个(
然后应用(…)
)方法

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());
}
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());
}
如果您的第三步不是示例性的,但看起来与问题中所示完全相同,则可以将其与代码路径连接步骤合并:

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);
}
public CompletionStage someMethod(SomeArgument SomeArgument){
CompletableFuture快捷方式=新建CompletableFuture();
CompletableFuture with chain=新的CompletableFuture();
CompletableFuture.runAsync(()->{
//Looooong手术
如果(某些条件)
withChain.complete(有效值);
其他的
快捷方式。完成(空);
});
连锁退货
。然后编写(结果->返回完成阶段(结果)的某些方法)
.applytoother(快捷方式,result->result==null?SomeResult.result\u 1:
result.someCondition()?SomeResult.result_2:SomeResult.result_3);
}

然后我们只跳过第二步,即返回CompletionStage调用的
SomeMethod,但它仍然可以代表一长串中间步骤,所有这些步骤都跳过了,而不需要通过nullcheck手动跳过。

为了完整性,我添加了一个新的答案

尽管@Holger提出的解决方案非常有效,但对我来说有点奇怪。我一直在使用的解决方案包括在不同的方法调用中分离不同的流,并使用
然后组合

public enum SomeResult {
    RESULT_1,
    RESULT_2,
    RESULT_3
}

public CompletionStage<SomeResult> someMethod(SomeArgument someArgument) {

    return CompletableFuture.supplyAsync(() -> {
        // loooooong operation
        if (someCondition)
            return operateWithValidValue(value);
        else
            return CompletableFuture.completedValue(ChainingResult.RESULT_1);
    })
        .thenCompose(future -> future);

public CompletionStage<SomeResult> operateWithValidValue(... value) {
     // more loooong operations...
     if (someCondition)
         return CompletableFuture.completedValue(SomeResult.RESULT_2);
     else
         return doFinalOperation(someOtherValue);   
}

public CompletionStage<SomeResult> doFinalOperation(... value) {
     // more loooong operations...
     if (someCondition)
         return CompletableFuture.completedValue(SomeResult.RESULT_2);
     else
         return CompletableFuture.completedValue(SomeResult.RESULT_3);
}
公共枚举结果{
结果1,
结果2,
结果3
}
公共CompletionStage someMethod(SomeArgument SomeArgument){
返回CompletableFuture.SupplySync(()->{
//Looooong手术
如果(某些条件)
返回操作的有效值(value);
其他的
返回CompletableFuture.completedValue(chainResult.RESULT_1);
})
.然后编写(未来->未来);
公共CompletionStage操作的有效值(…值){
//更多龙龙行动。。。
如果(某些条件)
返回CompletableFuture.completedValue(SomeResult.RESULT_2);
其他的
返回doFinalOperation(someOtherValue);
}
公共CompletionStage doFinalOperation(…值){
//更多龙龙行动。。。
如果(某些条件)
返回CompletableFuture.completedValue(SomeResult.RESULT_2);
其他的
返回CompletableFuture.completedValue(SomeResult.RESULT_3);
}
注意:为了得到更完整的答案,我更改了问题的算法


所有的长操作都可能被包装在另一个
CompletableFuture中。如果您只需要检查空值,则可以使用
Optional
解决。例如,您应该执行以下操作:

public Bar execute(String id) {

      return this.getFooById(id)
            .thenCompose(this::checkFooPresent)
            .thenCompose(this::doSomethingElse)
            .thenCompose(this::doSomethingElseMore)
            .thenApply(rankRes -> new Bar(foo));

}


private Optional<Foo> getFooById(String id) {

    // some better logic to retrieve foo

    return Optional.ofNullable(foo);
}


private CompletableFuture<Foo> checkFooPresent(Optional<Foo> optRanking) {

    CompletableFuture<Foo> future = new CompletableFuture();
    optRanking.map(future::complete).orElseGet(() -> future.completeExceptionally(new Exception("Foo not present")));
    return future;
}
公共条执行(字符串id){
返回此.getFooById(id)
.thenCompose(此::checkFooPresent)
.然后撰写(此::doSomethingElse)
.然后合成(此::doSomethingelsMore)
。然后应用(rankRes->newbar(foo));
}
私有可选getFooById(字符串id){
//检索foo的一些更好的逻辑
返回可选。未满(foo);
}
私有CompletableFuture checkFooPresent(可选操作传输){
CompletableFuture=新的CompletableFuture();
optRanking.map(future::complete).OrelGet(()->future.completeException(新异常(“Foo不存在”));
回归未来;
}
checkFooPresent()
接收一个
可选的
,如果其值为
null
则异常完成
CompletableFuture


显然,您需要管理该异常,但是如果您以前设置过
异常处理程序
或类似的程序,那么它应该是免费的。

它可以工作,谢谢!遵循相同的模式(创建几个
CompletableFuture
并使用
应用程序(…)
)那么就有可能将其扩展到多个路径,对吗?是的,您可以将其扩展到多个路径,但必须注意保持生成的代码的可维护性。也许这有助于将分支的逻辑封装到一个实用方法中,您可以多次使用。