问题描述
我有几个 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 null
passing 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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!