当 flatMap returns 为空 Mono 时如何调用 switchIfEmpty?

How to call switchIfEmpty when the flatMap returns an empty Mono?

我的标题听起来令人困惑,所以让我用一些命令式伪代码来解释我正在尝试做的事情

Mono<Void> func() {
  Mono<MyThing> myThing = getMyThing();
  if myThing is not empty:
    return doSomething();
  else:
    return doSomethingElse();
}

这是我尝试被动执行此操作时遇到的问题:

Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
  Mono<MyThing> myThing = getMyThing();
  return myThing
    .flatMap(thing -> {
      Mono<Void> somethingMono = doSomething();
      return somethingMono;
    })
    .switchIfEmpty(Mono.defer(() -> {
      Mono<Void> somethingElseMono = doSomethingElse();
      return somethingElseMono;
    });
}

这在 myThing 为空时工作正常。它跳过 .flatMap() 并执行 .switchIfEmpty() 语句。

但是,当myThing不为空时,它执行.flatMap(),这就是我想要的。但是 flatMap returns a Mono<Void> 会触发后续的 .switchIfEmpty() 方法。

我尝试交换 .flatMap().switchIfEmpty() 的位置,但这也不起作用,因为 .switchIfEmpty() returns 和 Mono<Void>.flatMap() 期望 Mono<MyThing>.

这似乎是一种常见模式,所以想知道执行此操作的正确方法是什么。

有几种方法可以做到这一点。由于您使用 Mono<Void> 作为 return 类型,您可以这样做:

getMyThing()
        .delayUntil(thing -> doSomething())
        .switchIfEmpty(doSomethingElse().cast(String.class))
        .then()

...但这不是最整洁或最清晰的恕我直言。它有点冗长,但我很想映射到一个可选的:

getMyThing().map(Optional::of).defaultIfEmpty(Optional.empty())
        .flatMap(thing -> thing.isPresent() ? doSomething() : doSomethingElse())
        .then()

如果您需要经常这样做,您可以考虑转换实用方法:

public static <T> Mono<Optional<T>> optional(Mono<T> mono) {
    return mono.map(Optional::of).defaultIfEmpty(Optional.empty());
}

...这样您就可以只执行 getMyThing().transform(Utils::optional) 而不是每次都执行显式映射/默认设置。