В чем разница между «Может быть» и «Необязательно» в rxjava2?

Док говорит

Концептуально это объединение Single и Completable, обеспечивающее средства для захвата шаблона эмиссии, где может быть 0 или 1 элемент или ошибка, сигнализируемая некоторым реактивным источником.

Но я не уверен, что это на самом деле означает. Кажется, это Optional java8.

Следующие два кода дают одинаковый результат, но я не знаю, что Maybe может сделать, а Optional не может (или громоздко).

  @Test
  public void testMaybe1() {
    Observable.just(3, 2, 1, 0, -1)
      .map(i -> {
        try {
          int result = 6 / i;
          return Maybe.just(result);
        } catch (Exception e) {
          return Maybe.empty();
        }
      })
      .blockingForEach(maybe -> {
          logger.info("result = {}", maybe.blockingGet());
        }
      );
  }


  @Test
  public void testMaybe2() {
    Observable.just(3, 2, 1, 0, -1)
      .map(i -> {
        try {
          int result = 6 / i;
          return Optional.of(result);
        } catch (Exception e) {
          return Optional.empty();
        }
      })
      .blockingForEach(opt -> {
          logger.info("result = {}", opt.orElse(null));
        }
      );
  }

Результаты те же:

result = 2
result = 3
result = 6
result = null
result = -6

В rxJava1 мой API возвращал Observable<Optional<T>>. Это неприятный запах? Должен ли я изменить на Observable<Maybe<T>> ?


person smallufo    schedule 05.11.2016    source источник


Ответы (4)


Maybe — это оболочка вокруг операции/события, которая может иметь либо

  1. Единый результат
  2. Безрезультатно
  3. Результат ошибки

Однако необязательный является оболочкой вокруг значения, которое может быть либо

  1. Подарок
  2. Отсутствующий

В вашем примере в операции map вычисление является синхронным (т.е. 6/i является синхронным и может немедленно привести к значению), и вы хотите распространить значение (если возможно деление) или пустое значение (если деление невозможно). Следовательно, использование Optional имеет больше смысла.

Однако есть и другие варианты:

  • Если вы хотите рассказать, почему деление невозможно, вам нужно сообщить о возникшем исключении. В таком случае использование Maybe будет иметь больше смысла.
  • Если вас не интересуют как пустое значение, так и причина ошибки, вы просто хотите пропустить распространение этих результатов. В таком случае я бы использовал flatMap вместо map. Тогда мне не придется использовать ни Optional, ни Maybe.

    .flatMap(i -> { 
      try { 
        int result = 6 / i; 
        return Observable.just(result); 
      } catch (Exception e) { 
        return Observable.empty(); 
      } 
    }) 
    

Maybe также полезен, когда у вас есть Observable, который может выдавать несколько значений, но вас интересует, скажем, только первое, и поэтому вы используете оператор firstElement() в Observable. Это возвращает Maybe, потому что либо есть одно значение, либо значение отсутствует (если исходный Observable не выдает никакого значения до завершения), либо есть ошибка (если исходный Observable ошибается перед выдачей любого значения).

person Praveer Gupta    schedule 05.11.2016
comment
Не обязательно асинхронное событие, может быть синхронным. - person Dave Moten; 07.11.2016
comment
@DaveMoten - Замечание принято и внесены изменения. Спасибо. - person Praveer Gupta; 07.11.2016

Maybe — это ленивый поток из нуля или одной вещи (и это может привести к ошибке). Optional не ленивый, он либо есть либо его нет. Нет смысла отложенного расчета с Optional, тогда как с Maybe есть.

person Dave Moten    schedule 07.11.2016

Разница, относящаяся к вашему вопросу, заключается в том, что Maybe может распространять ошибку, а Optional не может - в вашем примере нельзя различить ошибку и пустой результат. Если важна обработка ошибок, Optional бесполезен, а Maybe имеет Maybe.error(Throwable). С точки зрения API, для вашего варианта использования я бы предпочел Single вместо Maybe, потому что он дает либо ошибку, либо один результат, поэтому тип возврата будет Observable<Single<T>>

person m.ostroverkhov    schedule 05.11.2016

RxJava 2 нацелен на Java 6. Это означает, что встроенная поддержка Optional не гарантируется, и они должны приносить свои собственные. Подобно тому, как они должны приносить свои собственные Function типы.

Если ваше приложение/библиотека поддерживает только Java >= 8, вы можете использовать то, что вам больше подходит.

person Matthias247    schedule 05.11.2016