根据条件链接可完成的期货

Chaining completable futures based on conditions

我有一堆 return CompletableFuture 的方法,我想以特定的方式链接起来

package com.sandbox;

import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.stream.IntStream;

public class SandboxFutures {

    public CompletableFuture<Integer> generateRandom(int min, int max) {
        return CompletableFuture.supplyAsync(() -> {
            if (min >= max) {
                throw new IllegalArgumentException("max must be greater than min");
            }

            Random r = new Random();
            return r.nextInt((max - min) + 1) + min;
        });
    }

    public CompletableFuture<String> printEvenOrOdd(int result) {
        return CompletableFuture.supplyAsync(() -> {
            if (result % 2 == 0)
                return "Even";
            else
                return "Odd";
        });
    }

    public CompletableFuture<Integer> findFactorial(int evenNumber) {
        return CompletableFuture.supplyAsync(() -> {
            if (evenNumber <= 0) {
                return 0;
            }

            return IntStream.rangeClosed(2, evenNumber).reduce(1, (x,y) -> x*y);
        });
    }

    public CompletableFuture<Integer> convertToNearestEvenInteger(int oddNumber) {
        return CompletableFuture.supplyAsync(() -> {
           if (oddNumber <= 0) {
               return 2;
           }
           return oddNumber+1;
        });
    }

}

我正在尝试根据以下规则组合它们,

  1. 生成 1 到 100 之间的随机数
  2. 如果是偶数打印Even,如果是奇数打印Odd
  3. 如果号码是偶数,用随机数
  4. 调用findFactorial
  5. 如果数字是奇数通过convertToNearestEvenInteger
  6. 找到最近的偶数

我不太清楚如何进行条件链接和异常处理。一些示例或代码片段可能会有所帮助。

您可以使用 thenCompose():

CompletableFuture<Integer> n = generateRandom(1, 100)
        .thenCompose(i -> printEvenOrOdd(i)
                .thenCompose(s -> s.equals("Even")
                        ? findFactorial(i)
                        : convertToNearestEvenInteger(i)));
System.out.println(n.get());

但是,当生成大偶数时,您的阶乘方法无法存储任何大于 int 的数据,因此您需要更新它。

printEvenOrOdd 的书写方式使它比需要的更难。问题是它不打印这个词"Even"或"Odd",它returns它,这意味着原来的 result 丢失了。其余步骤取决于实际数字。要解决此问题,您可以使用 call printEvenOrOdd 然后使用 .thenApply(__ -> result) 恢复原始号码。它看起来像这样:

System.out.println(
    generateRandom(1, 100)
        .thenCompose(result ->
            printEvenOrOdd(result)
                .thenAccept(System.out::println)
                .thenApply(__ -> result)
        )
        .thenCompose(result ->
            result % 2 == 0
                ? findFactorial(result)
                : convertToNearestEvenInteger(result)
        )
        .join()
);

更好的解决方案是将 printEvenOrOdd 的定义更改为:

public CompletableFuture<Integer> printEvenOrOdd(int result) {
    return CompletableFuture.supplyAsync(() -> {
        System.out.println(result % 2 == 0 ? "Even" : "Odd");
        return result;
    });
}

这将使链接步骤 3 和 4 变得容易得多:

System.out.println(
    generateRandom(1, 100)
        .thenApply(this::printEvenOrOdd)
        .thenCompose(result ->
            result % 2 == 0
                ? findFactorial(result)
                : convertToNearestEvenInteger(result)
        )
        .join()
);