Administrando excepciones con flatMap

Administrando excepciones con flatMap


Como recomienda David Karnok en el artículo "flatMap part 1" y Dan Lew en el artículo "Error handling in Rxjava" para la administración de excepciones a través de flatMap se puede devolver el error directamente sin necesidad de envolverlo (wrapping). Esto aplica tanto para las excepciones tipo checked como las unchecked.


    
       Observable.range(1, 10)
                .flatMap(v -> {
                    if (v < 5) {
                        return Observable.just(v);
                    }
                    return Observable.error(new IOException("Why not?!"));
                })
                .subscribe(System.out::println, Throwable::printStackTrace);
Output:
1
2
3
4
java.io.IOException: Why not?!
    

Existe otra alternativa a través del uso de los argumentos del operador flatMap, sin embargo no es recomendable debido al costo de la operación, y además se debe tener cuidado en como se configura dentro del "chain de operadores".

Por ejemplo, en el siguiente código no se tiene efecto del manejo de la excepción:

    
       Observable.just(10)
                .flatMap(integer -> Observable.just(integer / 0), //Crash!
                        throwable -> Observable.error(new Exception("my custom error!")),
                        () -> Observable.just("complete"))
                .doOnError(throwable -> System.err.println("doOnError"))
                .subscribe(integer -> System.out.println(integer),
                        throwable -> System.err.println(throwable));

Output:
doOnError
java.lang.ArithmeticException: / by zero
    




Sin embargo, si el error se genera en el operador inmediatamente anterior al operador flatMap:

    
       Observable.just(10)
                .map(integer -> integer + 10/0) //Crash!
                .flatMap(integer -> Observable.just(integer),
                        throwable -> Observable.error(new Exception("my custom error!")),
                        () -> Observable.just("complete"))
                .doOnError(throwable -> System.err.println("doOnError"))
                .subscribe(integer -> System.out.println(integer),
                        throwable -> System.err.println(throwable));
Output:
doOnError
java.lang.Exception: my custom error!
    

Adicionalmente, si se requiere dar un manejo particular a la respuesta ante una excepción se puede utilizar el operador onErrorReturn:

    
       Observable.just(10)
                .map(integer -> integer + 10/0) //Crash!
                .flatMap(integer -> Observable.just(integer),
                        throwable -> Observable.error(new Exception("my custom error!")),
                        () -> Observable.just("complete"))
                .doOnError(throwable -> System.err.println("doOnError"))
                .onErrorReturn(error -> "Empty result")
                .subscribe(integer -> System.out.println(integer),
                        throwable -> System.err.println(throwable));
Output:
doOnError
Empty result
    




Thanks for your comment