与反应堆抛出异常的正确方法

问题描述 投票:9回答:1

我是新来的项目Reactor和反应式编程一般。

我目前正在在一张类似下面的代码:

Mono.just(userId)
    .map(repo::findById)
    .map(user-> {
        if(user == null){
            throw new UserNotFoundException();
        }
        return user;
    })
    // ... other mappings

这个例子可能是愚蠢的,有一定落实这种情况下,更好的方式,但问题是:

这是错误的使用throw new例外,在map块或者我应该用return Mono.error(new UserNotFoundException())代替呢?

有没有在做这两种方式中的任何实际的区别吗?

java reactive-programming project-reactor reactor
1个回答
31
投票

有一对夫妇的,可以被视为异常抛出的一种方便的方式方法:

Handle your element using Flux/Mono.handle

一的,可以简化其可能导致错误的或空的流的元素的处理的方式是操作者handle

下面的代码演示了如何使用它才能解决我们的问题:

Mono.just(userId)
    .map(repo::findById)
    .handle((user, sink) -> {
        if(!isValid(user)){
            sink.error(new InvalidUserException());
        } else if (isSendable(user))
            sink.next(user);
        }
        else {
            //just ignore element
        }
    })

我们可以看到,在.handle运营商需要通过BiConsumer<T, SynchronousSink<>为了处理一个元素。在这里,我们有我们的BiConsumer两个参数。第一个是从上游,其中,第二个是SynchronousSink这有助于我们同步供给元件到下游的元件。这种技术扩展到提供我们的元素的处理不同的结果的能力。例如,在情况下该元素是无效的,我们可以提供错误的相同SycnchronousSync将上游取消并产生onError信号到下游。反过来,我们可以“过滤器”使用相同的handle运营商。一旦手柄BiConsumer被执行,没有元素已经供应,反应堆将考虑作为类型的过滤,将请求对我们来说是额外的元素。最后,如果该元素是有效的,我们可以简单地调用SynchronousSink#next和下游传播我们的元素或应用一些关于它的映射,所以我们必须handle这里的map操作。此外,我们可以放心地使用该运营商没有性能影响,并提供复杂的元素验证,如元素或错误发送给下游验证。

Throws using #concatMap + Mono.error

其中的映射过程中抛出一个异常的选项是map更换concatMap。在本质上,concatMap做几乎同样的flatMap一样。唯一的区别是,concatMap允许一次只有一个子。这样的行为,简化内部实行了很多,不会影响性能。因此,我们可以使用下面的代码以抛出异常的一个功能更强大的方式:

Mono.just(userId)
    .map(repo::findById)
    .concatMap(user-> {
        if(!isValid(user)){
            return Mono.error(new InvalidUserException());
        }
        return Mono.just(user);
    })

另外,在上述中无效的用户的情况下,样品中,我们使用Mono.error返回异常。同样,我们可以使用Flux.error助焊剂做:

Flux.just(userId1, userId2, userId3)
    .map(repo::findById)
    .concatMap(user-> {
        if(!isValid(user)){
            return Flux.error(new InvalidUserException());
        }
        return Mono.just(user);
    })

请注意,在这两种情况下,我们返回的只有一个元素感冒流。在电抗器,有一对夫妇的改善情况下的性能优化的返回流是冷标量流。因此,建议使用流量/单声道concatMap + .justemptyerror因此,当我们需要更复杂的映射,可与return nullthrow new ...结束。

注意!永远不要检查为空传入的元素。该反应堆项目将永远不会给你发送一个null值,因为这违反了无流规范(见Rule 2.13)因此,在情况下,如果repo.findById返回null,反应堆将抛出NullPointerException为您服务。

Wait, Why concatMap is better than flatMap?

在本质上,flatMap被设计为合并从在时间执行所述多个子元件。这意味着flatMap应该有异步流之下的话,他们可能会在处理多个线程的数据,或者可能是几个网络调用。随后,这种预期的冲击实现了很多,所以flatMap应该能够处理来自多个流(Threads)数据(指并发数据结构的使用),排队元素如果存在来自另一个流的排水(用于Queues附加存储器分配每个子),不违反无流规范规则(指非常复杂的实现)。计算所有这些事实,我们更换一个普通map操作(这是同步的)事实在使用Flux/Mono.error(不更改执行的同步性)抛出异常的更方便的方法会导致这样的事实,我们不需要这样的复杂的操作,我们可以使用它在一个时间设计为单流的异步处理,并有几个优化,以处理标量,寒溪水简单得多concatMap

Throws exception using switchOnEmpty

因此,另一种方法抛出一个异常时,则结果为空是switchOnEmpty操作。下面的代码演示了如何使用这种方法:

Mono.just(userId)
    .flatMap(repo::findById)
    .switchIfEmpty(Mono.error(new UserNotFoundExeception()))

正如我们所看到的,在这种情况下repo::findById应该有Mono User作为返回类型。因此,万一User实例不会被发现,结果流将是空的。因此,反应器将调用一个替代Mono,指定为switchIfEmpty参数。

Throw your exception as is

它可算作一个不太可读的代码或不好的做法,但你可以把你的异常,因为是。这种模式违反了无流规范,但反应器将捕捉抛出的异常,为您和传播它作为onError信号到你的下游

Takeaways

  1. 使用.handle运营商,以提供复杂的元素处理
  2. 当我们需要的映射,但这样的技术是最适合于异步元件处理的情况下,过程中引发异常使用concatMap + Mono.error
  3. 使用qazxsw POI + qazxsw POI的时候,我们已经有了qazxsw POI到位
  4. flatMap的返回类型是在你的下游Mono.error禁止的所以不是flatMap你会得到与Null意外null
  5. 使用map在所有情况下,当你需要的,如果调用一些特定功能的结果与空流完成后发送错误信号
© www.soinside.com 2019 - 2024. All rights reserved.