与CompletableFuture异步后如何保持干净的代码流?

问题描述 投票:1回答:1

我遇到了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没有这种功能。

java asynchronous async-await java-stream completable-future
1个回答
0
投票

正如评论部分中的人们所提到的,没有什么可以做的。

但是,我将通过指向另一个堆栈的链接来结束这一点,该堆栈被证明是非常有用的,并解决了我未明确提及的另一个问题。即,如何在处理此警告时将值从上一阶段转发出去:

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

© www.soinside.com 2019 - 2024. All rights reserved.