Rx Java - Использование Single.Error / Observable.error против исключения исключения - PullRequest
0 голосов
/ 07 мая 2020

Недавно я начал использовать RxJava2 в одном из моих проектов и в настоящее время работаю над реализацией в нем обработки ошибок.

Ниже я написал фиктивный класс, в котором я изначально выдавал ошибку после того, как заключил ее в пользовательское исключение. Однако в некоторых из примеров, с которыми я сталкивался при обработке ошибок в stackoverflow и других сайтах, вместо этого использовалось Single.error.

Я использовал оба подхода, и в результате метод onError моих подписчиков был вызван с исключением / by zero. Я не заметил никакой разницы между ними.

Существует исчерпывающая документация по Обработке ошибок и Операторам обработки ошибок , а также множество других статей о том, как обрабатывать исключение после его создания. Но информация в javado c для Single.error и Observable.error довольно минимальна.

Есть ли преимущество использования Single.error или Observable.error просто выбросить исключение? Когда мы выбираем один подход перед другим?

public class Test {

  public  static void main(String[] args){
    Single.just(1)
        .flatMap(x -> externalMethod(x))
        .subscribe(
            s -> System.out.println("Success : " + s),
            e -> System.out.println("Error : "+e)
            );
  }

  public static Single<Integer> externalMethod(int x){
    int result = 0;
    try{
      /* Some database / time consuming logic */
      result = x % 0;
    }
    catch (Exception e){
      throw new CustomException(e.getMessage());                // --> APPROACH 1
                    OR
      return Single.error(new CustomException(e.getMessage())); // --> APPROACH 2
    }
    return Single.just(result);
  }
}

1 Ответ

0 голосов
/ 08 мая 2020

На самом деле это не имеет значения, потому что Rx Java пытается поймать и ретранслировать все Throwables

ПОДХОД 1 - выбросить новое CustomException (); (io.reactivex.internal.operators.single.SingleFlatMap)

    @Override
    public void onSuccess(T value) {
        SingleSource<? extends R> o;

        try {
            o = ObjectHelper.requireNonNull(mapper.apply(value), "The single returned by the mapper is null");
        } catch (Throwable e) {
            Exceptions.throwIfFatal(e);
            downstream.onError(e);
            return;
        }

        if (!isDisposed()) {
            o.subscribe(new FlatMapSingleObserver<R>(this, downstream));
        }
    }

Вы видите, что данный сопоставитель из flatMap вызывается с помощью try-catch. Если сопоставитель выбрасывает Throwable, Throwable будет перенаправлен через onError нижестоящему подписчику.

ПОДХОД 2 - return Single.error (...) (io.reactivex.internal.operators.single .SingleError)

Single # error

@Override
protected void subscribeActual(SingleObserver<? super T> observer) {
    Throwable error;

    try {
        error = ObjectHelper.requireNonNull(errorSupplier.call(), "Callable returned null throwable. Null values are generally not allowed in 2.x operators and sources.");
    } catch (Throwable e) {
        Exceptions.throwIfFatal(e);
        error = e;
    }

    EmptyDisposable.error(error, observer);
}


public static void error(Throwable e, SingleObserver<?> observer) {
    observer.onSubscribe(INSTANCE);
    observer.onError(e);
}

Single # error выдает данный Throwable по подписке через # onError

Когда значение передается в Single # flatMap сопоставитель применяется, и открывается подписка, возвращаемое значение от сопоставителя.

(io.reactivex.internal.operators.single.SingleFlatMap.SingleFlatMapCallback.FlatMapSingleObserver)

        @Override
        public void onSubscribe(final Disposable d) {
            DisposableHelper.replace(parent, d);
        }

        @Override
        public void onError(final Throwable e) {
            downstream.onError(e);
        }

Возвращенное значение Single возвращает ошибку Single #, которая генерирует Throwable через #onError. Данная ошибка #onError будет делегирована нижестоящему подписчику через onError.

С точки зрения производительности один может быть быстрее другого, но это должно быть измерено, чтобы получить точное изображение. При возврате ошибки Single # выполняется больше распределений и больше методов в стеке (subscribeActual). С другой стороны, при броске метательного предмета его нужно поймать и направить.

...