我遇到了CompletableFutures的问题。我有一个基于API的基于JAX RS的REST端点,我需要对该API进行3次连续调用。电流看起来像这样:
FruitBasket fruitBasket = RestGateway.GetFruitBasket("today");
Fruit chosenFruit = chooseFruitFromBasket(fruitBasket);
Boolean success = RestGateway.RemoveFromBasket(chosenFruit);
if (success) {
RestGateway.WhatWasRemoved(chosenFruit.getName());
} else {
throw RuntimeException("Could not remove fruit from basket.");
}
return chosenFruit
当然,每个对RestGateway.SomeEndpoint()
的调用都被阻止,因为它在构建我的请求时不使用.async()
。
所以现在让我们添加.async()
并从每个RestGateway
交互中返回CompletableFuture。
我最初的想法是这样做:
Fruit chosenFruit;
RestGateway.GetFruitBasket("today")
.thenCompose(fruitBasket -> {
chosenFruit = chooseFruitFromBasket(fruitBasket);
return RestGateway.RemoveFromBasket(chosenFruit);
})
.thenCompose(success -> {
if(success) {
RestGateway.WhatWasRemoved(chosenFruit);
} else {
throw RuntimeException("Could not remove fruit from basket.");
});
return chosenFruit;
因为这似乎向我保证执行将顺序进行,并且如果前一阶段失败,则其余阶段将失败。
不幸的是,这个例子很简单,并且比我的实际用例少了很多阶段。感觉就像我在堆叠的.thenCompose()
块中编写了很多嵌套条件。有什么办法可以将其划分为多个部分吗?
我正在寻找的类似于原始代码:
FruitBasket fruitBasket = RestGateway.GetFruitBasket("today").get();
Fruit chosenFruit = chooseFruitFromBasket(fruitBasket);
Boolean success = RestGateway.RemoveFromBasket(chosenFruit).get();
if (success) {
RestGateway.WhatWasRemoved(chosenFruit.getName()).get();
} else {
throw RuntimeException("Could not remove fruit from basket.");
}
return chosenFruit
但是对.get()
的呼叫阻塞了!因此,异步重写RestGateway绝对没有任何好处!
TL; DR-有什么方法可以保留原始代码流,同时获取异步非阻塞Web交互的好处?我看到的唯一方法是从CompletableFuture库中级联许多.thenApply()
或.thenCompose
方法,但必须有更好的方法!
I think此问题已由JavaScript中的await()
解决,但我认为Java没有这种功能。
正如评论部分中的人们所提到的,没有什么可以做的。
但是,我将通过指向另一个堆栈的链接来结束这一点,该堆栈被证明是非常有用的,并解决了我未明确提及的另一个问题。即,如何在处理此警告时将值从上一阶段转发出去:
variable used in lambda expression should be final or effectively final
。
Using values from previously chained thenCompose lambdas in Java 8
我最终得到这样的东西:
CompletableFuture<Boolean> stepOne(String input) {
return RestGateway.GetFruitBasket("today")
.thenCompose(fruitBasket -> {
Fruit chosenFruit = chooseFruitFromBasket(fruitBasket);
return stepTwo(chosenFruit);
});
}
CompletableFuture<Boolean> stepTwo(Fruit chosenFruit) {
return RestGateway.RemoveFromBasket(chosenFruit)
.thenCompose(success -> {
if (success) {
return stepThree(chosenFruit.getName());
} else {
throw RuntimeException("Could not remove fruit from basket.");
}
});
}
CompletableFuture<Boolean> stepThree(String fruitName) {
return RestGateway.WhatWasRemoved(fruitName);
}
假设RestGateway.WhatWasRemoved()
返回Boolean
。