简体   繁体   English

停止供应商内部的 CompletableFuture 链接

[英]Stop CompletableFuture chaining inside the Supplier

I have such an operation,我有这样的手术,

public void createFuture() {
    CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 5);
    future.thenApply(i -> {
        if (i == 5) {
            System.out.println("hello, i equals to 5 so expensive operations are unnecessary");
        }
        return i;
    }).thenApply(i -> {
        if (i != 5) {
            System.out.println("Expensive operation");
        }
        return i;
    }).thenApply(i -> {
        if (i != 5) {
            System.out.println("Expensive operation");
        }
        return i;
    }).thenApply(i -> {
        if (i != 5) {
            System.out.println("Expensive operation");
        }
        return i;
    }).thenApply(i -> {
        if (i != 5) {
            System.out.println("Expensive operation");
        }
        return i;
    });

}

Here in the first block, I check some condition (i == 5) and if it is true, I don't need the rest of the operations.在第一个块中,我检查了一些条件(i == 5) ,如果它为真,则不需要其余的操作。 I don't want to throw an exception to cancel the rest because this is not an exceptional situation.我不想抛出异常来取消其余部分,因为这不是特殊情况。 Is there a nice way to do it other than passing some boolean to each operation?除了向每个操作传递一些布尔值之外,还有其他好的方法吗?

CompletableFuture does not have mechanisms to support conditional statements. CompletableFuture没有支持条件语句的机制。 In your case the code can be simplified by extracting all tasks for i != 5 into one CompletableFuture with thenCompose .在您的情况下,可以通过使用thenCompose i != 5所有任务提取到一个CompletableFuture来简化代码。

Other workaround would be to create a map, filter it and create a completable future with it:其他解决方法是创建一个地图,过滤它并用它创建一个完整的未来:

Map<Predicate<Integer>, Runnable> m = Map.of(
    integer -> integer == 5,
    () -> System.out.println("Task 1"),
    integer -> integer != 5,
    () -> System.out.println("Task 2"),
    integer -> integer != 5,
    () -> System.out.println("Task 3")
);
CompletableFuture[] runnables = m.entrySet().stream()
    .filter(e -> e.getKey().test(5))
    .map(Map.Entry::getValue)
    .map(CompletableFuture::runAsync)
    .toArray(CompletableFuture[]::new);
CompletableFuture composed = CompletableFuture.allOf(runnables);

Here I'm creating a map Predicate -> Runnable .在这里,我正在创建一个地图Predicate -> Runnable Then I'm filtering out all pairs that do not fulfill the predicate and wrapping runnables into CompletableFuture s.然后我过滤掉所有不满足谓词的对,并将 runnable 包装到CompletableFuture At the end composed is a CompletableFuture , that is composed of all the desired runnables.最后composedCompletableFuture ,它由所有所需的 runnable 组成。

CompletableFuture.thenCompose() should do the trick. CompletableFuture.thenCompose()应该可以解决问题。

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ExecutionException;

class Scratch {

  public static void main(String[] args) throws ExecutionException, InterruptedException {
    CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 5);
    CompletableFuture<Integer> composed = future.thenCompose(number -> {
      if (number == 5)
        return simpleFuture(number);
      else
        return complexFuture(number);
    });
    System.out.println(composed.get());
  }

  private static CompletionStage<Integer> complexFuture(Integer number) {
    return CompletableFuture.completedFuture(number)
        .thenApply(i -> {
          System.out.println("I am expensive");
          return i;
        });
  }

  private static CompletableFuture<Integer> simpleFuture(Integer number) {
    return CompletableFuture.completedFuture(number)
        .thenApply(i -> {
          System.out.println("I am cheap");
          return i;
        });
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM