Цепочка завершаемых фьючерсов на основе условий - PullRequest
1 голос
/ 08 марта 2019

У меня есть куча методов, которые возвращают 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 ]

1 голос
/ 08 марта 2019

Вы можете использовать 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, поэтому вам необходимо его обновить.

0 голосов
/ 08 марта 2019

Способ написания 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()
);
...