简体   繁体   English

如何处理 RxJava 中的错误?

[英]how to handle errors in RxJava?

It may sound funny or maybe novice, but I don't understand what it means that something "failed" in Reactive Programming.这听起来可能很有趣,也可能是新手,但我不明白反应式编程中的“失败”是什么意思。 Do you mean a null?你的意思是null? An empty object?一个空的 object? someone could please give me examples.有人可以给我例子。

Some of the scenarios I wish to realize are:我希望实现的一些场景是:

Assuming I send a query parameter and get either a listing with values or an empty listing;假设我发送一个查询参数并获得一个带有值的列表或一个空列表; and lastly, I do not send the query parameter.最后,我不发送查询参数。

  • If an empty listing is issued I want to return an exception and a 404 status code.如果发布了一个空列表,我想返回一个异常和一个 404 状态码。

  • If they do not send the query parameter I want to return an exception and some status code.如果他们不发送查询参数,我想返回一个异常和一些状态码。

And of course, if a list with values is found, return it.当然,如果找到带有值的列表,则返回它。 Will it be possible to make these cases in a single method?是否有可能用一种方法制作这些案例? how do I do it?我该怎么做?

First, a reactor operator can ends in different ways:首先,reactor 操作符可以以不同的方式结束:

  1. Completes successfully after emitting one (Mono) or more (Flux) value(s)发射一个(单声道)或多个(通量)值后成功完成
  2. Completes empty : The pipeline sends completion signal, but no value has been emitted Completes empty :管道发送完成信号,但没有发出任何值
  3. Completes in error : somewhere in the pipeline, an error happened.错误完成:管道某处发生错误。 By default, as in imperative code, it stops the chain of operations, and is propagated.默认情况下,与命令式代码一样,它会停止操作链并进行传播。
  4. Cancelled: the pipeline might be interrupted by a manual action or a system shutdown.已取消:管道可能因手动操作或系统关闭而中断。 It then ends in error (a special kind of error, but an error nonetheless)然后它以错误结束(一种特殊的错误,但仍然是错误)

Secondly, reactive-stream, whatever the implementation (RxJava or Reactor) does not accept null values.其次,反应流,无论实现(RxJava 或 Reactor)接受 null 值。 It means that trying to produce a null value in/from a reactive stream will either cause an error or an undefined behavior.这意味着尝试在/从反应式 stream 中生成 null 值将导致错误或未定义的行为。 This is stated in reactive-stream specification, rule 2.13 :这在反应流规范规则 2.13 中有说明:

Calling [...] onNext [...] MUST return normally except when any provided parameter is null in which case it MUST throw a java.lang.NullPointerException to the caller调用 [...] onNext [...] 必须正常返回,除非任何提供的参数是null在这种情况下,它必须向调用者抛出 java.lang.NullPointerException

Let's try to produce some simple examples first.让我们首先尝试制作一些简单的示例。

This program shows the possible ways a pipeline can complete:该程序显示了管道可以完成的可能方式:

// Reactive streams does not accept null values:
try {
    Mono.just(null);
} catch (NullPointerException e) {
    System.out.println("NULL VALUE NOT ACCEPTED !");
}

// Mono/Flux operations stop if an error occurs internally, and send it downstream
try {
    Mono.just("Something")
        .map(it -> { throw new IllegalStateException("Bouh !"); })
        .block();
} catch (IllegalStateException e) {
    System.out.println("Error propagated: "+e.getMessage());
}

// A mono or a flux can end "empty". It means that no value or error happened.
// The operation just finished without any result
var result = Mono.just("Hello !")
        .filter(it -> !it.endsWith("!"))
        // Materialize allow to receive the type of signal produced by the pipeline (next value, error, completion, etc.)
        .materialize()
        .block();
System.out.println("Input value has been filtered out. No 'next' value " +
        "received, just 'completion' signal:" + result.getType());

Its output:其 output:

NULL VALUE NOT ACCEPTED !
Error propagated: Bouh !
Input value has been filtered out. No 'next' value received, just 'completion' signal:onNext

Then, let's look at a program that intercept empty pipelines and errors, and handle them gracefully:那么,我们来看一个拦截空流水线和错误,并优雅处理的程序:

// Errors can be intercepted and replaced by a value:
var result = Mono.error(new IllegalStateException("No !"))
        .onErrorResume(err -> Mono.just("Override error: Hello again !"))
        .block();
System.out.println(result);

// Empty pipelines can also be replaced by another one that produce a value:
result = Mono.just("Hello !")
        .filter(it -> !it.endsWith("!"))
        .switchIfEmpty(Mono.just("Override empty: Hello again !"))
        .block();

System.out.println(result);

It produces:它产生:

Override error: Hello again !
Override empty: Hello again !

With all this tools, we can solve the problem you describe with your query.使用所有这些工具,我们可以解决您在查询中描述的问题。

Let's mimic it:让我们模仿它:

public static Flux<String> processRequest(String queryParam) {
    if (queryParam == null || queryParam.isEmpty()) return Flux.error(new IllegalArgumentException("Bad request"));
    return Mono.just(queryParam)
               .flatMapMany(param -> Flux.fromArray(param.split("_")))
               .switchIfEmpty(Mono.error(new IllegalStateException("No data")));
}

public static void main(String[] args) {
    
    String[] inputs = { null, "hello_world", "___" };
    
    for (var input : inputs) {
        try {
            String result = processRequest(input)
                    .collect(Collectors.joining(", ", "[", "]"))
                    .block();
            System.out.println("COMPLETED: " + result);
        } catch (Exception e) {
            System.out.println("ERROR: " + e.getMessage());
        }
    }
}

It prints:它打印:

ERROR: Bad request
COMPLETED: [hello, world]
ERROR: No data

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM