Возврат нулевого значения в .map () против .flatMap () в Reactor - PullRequest
2 голосов
/ 03 октября 2019

Работает следующий фрагмент кода:

// emitting employees...
.flatMap(employee -> {

    boolean isAlive = employee.isAlive();

    return Mono.just(isAlive)

            .flatMap(myBoolean -> {
                if (myBoolean) {
                    return Mono.empty();
                } 
                else {
                    return Mono.just(employee);
                }
            });

})

Но мне было интересно, почему я не могу использовать .map при обработке myBoolean (исключение NullPointerException, когда возвращается ноль)

            .map(myBoolean -> {
                if (myBoolean) {
                    return null;
                } 
                else {
                    return employee;
                }
            });

Мне кажется, мне не хватает понимания о map против flatMap

В потоках Java 8 я понимаю разницу между map и flatMap (для каждого полученного элемента, map испускает 1, flatMap испускает N)

Но в Reactor я немного запутался. Я думал, что и map, и flatMap испускают 1 элемент для каждого полученного элемента, разница будет в том, что map испускает его как Mono, а flatMap нет. Чтобы испустить N предметов, я бы использовал flatMapMany.

Заранее спасибо за ваши объяснения!

Ответы [ 4 ]

2 голосов
/ 03 октября 2019

Из Reactor java doc

map: преобразовать элемент, испускаемый этим моно, применяя к нему синхронную функцию.

flatMap: преобразоватьэлемент, испускаемый этим Mono асинхронно, возвращая значение, испущенное другим Mono.

Во всех случаях вы не можете вернуть null. Это просто запрещено дизайном. Основное различие между map и flatMap заключается в том, что второй возвращает Mono. Это позволяет выполнять асинхронный вызов чего-то вроде базы данных, веб-службы и т. Д.

Поэтому flatMap следует использовать для выполнения другой асинхронной операции. Это не очень полезно, если вы возвращаете Mono.just(...). Мы можем использовать flatMap для возврата Mono.empty() в некоторых условиях, как вы это сделали. Это частая схема.

Здесь альтернативный код для создания нового объекта с условием:

        .handle(myBoolean, sink -> {
            if (!myBoolean) {
                sink.next(employee);
            } // else the Mono would be empty ...
        });
2 голосов
/ 03 октября 2019

При отображении содержимого Mono с использованием метода карты вы не можете предоставить значение null в качестве результата отображения, поскольку это приведет к java.lang.NullPointerException: The mapper returned a null value. во время подписки.

Mono может быть либопустой или должен содержать действительный объект.

Согласно исходному коду Project Reactor, содержимое Mono не может быть нулевым.

Таким образом, в этом случае действительное решение использует flatMap.

1 голос
/ 03 октября 2019

Это потому, что flatMap попытается развернуть внутренний моно во внешний моно. Значение будет нулевым, но будет тип.

С другой стороны, map преобразует Mono<A> в Mono<B>. null не имеет типа, и поэтому вы не можете этого сделать.

0 голосов
/ 07 октября 2019

A null в любом месте вашего потока выдаст NPE: Mapper returned a null value. Неважно map или flatMap. Это по замыслу.

Короткая заметка о flatMap: он охотно подписывается на свои внутренние потоки (в вашем случае Mono.empty() или Mono.just(..)) и выполняет динамическое объединение, поскольку внутренние потоки продолжают излучать элементы. Вот почему вы можете гарантировать заказ с flatMap.

...