为什么 Reactor Mono<Void> 被识别为一个空的 Mono?

Why Reactor Mono<Void> is recognized as an empty 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 具有以下 class MonoEmpty that is returned by a Mono.empty() method。最重要的是,该方法说明如下:

/**
 * 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();
}

没有发出任何项目 - 但我用 then() 方法发出了 Void 类型的对象。

这是什么解释?

好的,答案在 official java docThe Void class is an uninstantiable placeholder class to hold a reference to the Class object representing the Java keyword void

这意味着它的主要思想是简单地将 void return 类型表示为 class 并包含一个 Class<Void> public 值。而已。此外,它不可实例化,因为构造函数是私有的。所有这一切随后意味着我们可以分配给 Void 变量的唯一值是 null 始终被识别为 empty Mono.

有益的讨论: Java generics void/Void types

给定的 Mono 可以在发送完成信号之前不发布任何内容或单个值。 (它不能发布 null - 反应规范禁止它。) Mono 的泛型类型表示 可能 被发射的对象的类型 -但不能保证它 被发射。

例如,Mono<Foo> 可以只发出一个完成信号,或者 Foo 的一个实例,然后发出一个完成信号。

有两种可能无法发布值的常见情况 - 第一种是值可能存在也可能不存在(例如在数据库或集合中搜索项目)。在那种情况下,您仍然会使用 Mono<SomeType>,它可能会或可能不会发出 SomeType 实例。第二种情况是,如果某个值肯定 永远不会 被发布(通常在您只需要通知任务已完成时使用),那么按照惯例,Mono<Void> 是总是被使用。 then(),在你上面的例子中,属于第二种情况。

Mono<Void> 是特例的原因是,正如您所指出的,Void 是一个 class,永远无法通过设计实例化。因此,不存在 Void 的实例,这意味着 Mono 永远不会在其完成信号之前发出值。

因此,合乎逻辑的结论是 Mono<Void> 类型的发布者永远不会发出值,只能发出完成信号 - 因此它被用作这样。