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

时间:2019-03-08 04:24:56

标签: java asynchronous exception completable-future conditional-execution

我有一堆返回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. 如果该数字甚至用随机数呼叫findFactorial
  4. 如果数字是奇数,则通过convertToNearestEvenInteger查找最接近的偶数

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

2 个答案:

答案 0 :(得分:1)

您可以使用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的任何内容,因此您需要对其进行更新。

答案 1 :(得分:0)

printEvenOrOdd的编写方式使其变得比原来更加困难。问题是它没有打印单词“偶数”或“奇数”,而是返回,这意味着原始的result丢失了。其余步骤依赖于实际数字。要解决此问题,可以使用呼叫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()
);