弹簧反应器:单.zip空单晶时失效编辑

2022-09-02 01:01:03

我正在使用Spring Reactor 3.1.0.M3,并且有一个用例,我需要合并来自多个来源的Mono。我发现,如果其中一个Monos是空的Mono,zip会失败而不会出错。

例:

Mono<String> m1 = Mono.just("A");
Mono<String> m2 = Mono.just("B");
Mono<String> m3 = Mono.empty();

Mono<String> combined = Mono.zip(strings -> {
    StringBuffer sb = new StringBuffer();
    for (Object string : strings) {
        sb.append((String) string);
    }
    return sb.toString();
}, m1, m2, m3);
System.out.println("Combined " + combined.block());

添加 m3 时,在响应为 null 时跳过组合器。当我删除m3时,它一切都按预期工作,并返回“AB”。有没有办法通过检测空的Mono来处理这个问题?另外,有没有办法让组合器方法知道对象的类型,而不必强制转换?


答案 1

zip 运算符的行为与此不同。这实际上是违反直觉的:你的代码期望一个包含3个元素的元组,而你只得到两个?!?

在这种情况下,您可以控制,如果没有提供任何值,则只有您可以决定什么是好的默认值(请记住,反应流规范禁止的值)。null

Mono<String> m1 = Mono.just("A");
Mono<String> m2 = Mono.just("B");
Mono<String> m3 = Mono.empty().defaultIfEmpty("");

Mono<String> combined = Mono.when(m1, m2, m3).map(t -> {
    StringBuffer sb = new StringBuffer();
    sb.append(t.getT1());
    sb.append(t.getT2());
    sb.append(t.getT3());
    return sb.toString();
});

编辑

您似乎对类型的性质感到困惑,请参阅:Publisher

如果其中一个 Mono 是空 Mono,则 zip 失败且没有错误

因此,如果我尝试压缩Mono,并且由于某种原因,其中一个是空的,zip将失败,我似乎无法输入任何代码来防止这种情况

空不是失败情况:只是没有发出任何值并且成功完成。您可以通过更改代码示例来验证这一点:Mono

    combined.subscribe(
            s -> System.out.println("element: " + s), // doesn't execute
            s -> System.out.println("error: " + s), // doesn't execute
            () -> { System.out.println("complete!"); // prints
    });

因此,根据您的要求,您可以:

  • 对这 3 个实例应用运算符(如果有方便的默认值,您可以依赖)defaultIfEmptyMono
  • 使用默认值对组合应用运算符,甚至将其转换为错误消息defaultIfEmptyMonocombined.switchIfEmpty(Mono.error(...))

答案 2

在这种情况下,很容易为空情况定义一个默认值,该默认值可以很好地解决问题,如Brian的答案中所述。但是,对于其他自定义类型,由于某种原因,可能很难创建空对象。对于这些情况,另一种方法是使用 。不过,此解决方案有一些繁重的样板。StringOptional

Mono<Optional<String>> m1 = Mono.just("A").map(Optional::of).defaultIfEmpty(Optional.empty());
Mono<Optional<String>> m2 = Mono.just("B").map(Optional::of).defaultIfEmpty(Optional.empty());
Mono<Optional<String>> m3 = Mono.<String>empty().map(Optional::of).defaultIfEmpty(Optional.empty());

Mono<String> combined = Mono.zip(strings -> {
    StringBuffer sb = new StringBuffer();
    for (Object string : strings) {
        ((Optional<String>) string).ifPresent(sb::append);
    }
    return sb.toString();
}, m1, m2, m3);
System.out.println("Combined " + combined.block());

推荐