Почему Reactor Mono ‹Void› распознается как пустой Mono?

Вот фрагмент кода

@Test
public void test_mono_void_mono_empty() {
    Mono.just("DATA")
        .flatMap(s -> Mono.just(s.concat("-")
                                 .concat(s))
                          .doOnNext(System.out::println)
                          .then())
        .switchIfEmpty(Mono.just("EMPTY")
                           .doOnNext(System.out::println)
                           .then())
        .block();
}

что дает на консоль следующий результат:

DATA-DATA
EMPTY

Это означает, что цепочка в первом flatMap была признана пустой.

С другой стороны, у Reactor есть следующий класс MonoEmpty, который возвращается Mono.empty() метод. Кроме того, метод говорит следующее:

/**
 * Create a {@link Mono} that completes without emitting any item.
 *
 * <p>
 * <img class="marble" src="doc-files/marbles/empty.svg" alt="">
 * <p>
 * @param <T> the reified {@link Subscriber} type
 *
 * @return a completed {@link Mono}
 */
public static <T> Mono<T> empty() {
    return MonoEmpty.instance();
}

без генерации какого-либо элемента - но я выдал Void типизированный объект с помощью then() метода.

Какое этому объяснение?


person Serhii Povísenko    schedule 05.12.2019    source источник
comment
s.concat("-").concat(s), вероятно, следует записать как s + "-" + s   -  person Lino    schedule 05.12.2019
comment
@LinosaysReinstateMonica не вижу разницы   -  person Serhii Povísenko    schedule 05.12.2019
comment
+ может быть оптимизирован компилятором, тогда как с concat() у вас нет такой гарантии: stackoverflow.com/a/47626/5515060   -  person Lino    schedule 05.12.2019
comment
Я не имел в виду никакой разницы в объеме вопроса. Как это связано с темой?   -  person Serhii Povísenko    schedule 05.12.2019
comment
Это не так, но должно ли это быть? Я просто предложил улучшение   -  person Lino    schedule 05.12.2019


Ответы (2)


Хорошо, ответ находится в официальный java-документ, в котором написано The Void class is an uninstantiable placeholder class to hold a reference to the Class object representing the Java keyword void.

Это означает, что его основная идея состоит в том, чтобы просто представить тип возвращаемого значения void как класс и содержать Class<Void> общедоступное значение. Вот и все. Кроме того, его нельзя создать, поскольку конструктор является частным. Все это впоследствии означает, что единственное значение, которое мы можем присвоить переменной Void, - это null, что всегда распознается как empty Mono.

полезное обсуждение: универсальные Java-шаблоны типа void / Void

person Serhii Povísenko    schedule 05.12.2019
comment
единственное значение, которое мы можем присвоить переменной Void, - это null, что всегда распознается как пустой Mono - осторожно с этим; он может неуловимо упускать из виду то, что здесь происходит. Вы вообще не можете распространять null через реактивный поток, но вы можете просто ничего не распространять до сигнала завершения (что подразумевает Mono<Void>). - person Michael Berry; 08.12.2019

Данный Mono может либо ничего не публиковать, либо одно значение перед отправкой сигнала завершения. (Он не может публиковать null - это запрещено реактивной спецификацией.) Общий тип Mono обозначает тип объекта, который может быть испущен, но нет никакой гарантии, что он будет быть испущенным.

Например, Mono<Foo> может выдавать только сигнал завершения или экземпляр Foo, а затем сигнал завершения.

Существует два распространенных сценария, в которых значение не может быть опубликовано: первый - если значение может существовать или не существовать (например, поиск элемента в базе данных или коллекции). В этом случае вы все равно будете использовать Mono<SomeType>, и он может или не может испустить экземпляр SomeType. Второй сценарий: значение определенно никогда не будет опубликовано (часто используется, когда вам просто нужно уведомление о завершении задачи), и для этого по соглашению всегда используется Mono<Void>. then() в приведенном выше примере относится ко второму случаю.

Причина того, что Mono<Void> является особым случаем, заключается в том, что, как вы указываете, Void - это класс, который никогда не может быть создан по дизайну. Следовательно, не существует такой вещи, как экземпляр Void, что означает, что Mono никогда не может выдать значение до своего сигнала завершения.

Следовательно, логический вывод состоит в том, что издатель типа Mono<Void> никогда не может выдать значение, только сигнал завершения - и поэтому он используется как таковой.

person Michael Berry    schedule 07.12.2019