Неожиданный вывод типа с RxJava - PullRequest
0 голосов
/ 13 июня 2018

У меня есть обычный Transformer, который просто фильтрует список, используя заданный Предикат:

public class ListFilter<T> implements Observable.Transformer<List<T>, List<T>> {
    private final Predicate<T> predicate;

    private ListFilter(Predicate<T> predicate) {
        this.predicate = predicate;
    }

    public static <T> Observable.Transformer<List<T>, List<T>> create(Predicate<T> predicate) {
        return new ListFilter<>(predicate);
    }

    @Override
    public Observable<List<T>> call(Observable<List<T>> listObservable) {
        return listObservable
                .flatMap(list -> Observable.from(list)
                        .filter(predicate::test)
                        .toList());
    }
}

Теперь я могу отфильтровать список элементов с минимальным шаблоном, как это:

repository.observeItems() // returns Observable<List<SomeItem>>
        .compose(ListFilter.create(item -> /* some filter logic */)

Но есть кое-что, что я не могу объяснить:

List<? extends Dummy> list = SomeDummyFactory.create();
BehaviorSubject<List<? extends Dummy>> subject = BehaviorSubject.create(list);

// #1 -> ok
BehaviorSubject.create(list)
    .compose(ListFilter.create(item -> /* `item` is `Dummy` */)
    ...

// #2 -> error
subject
    .compose(ListFilter.create(item -> /* `item` is `Object` */)) 
    ...

// #3 -> ok
subject
    .map(any -> any) // do nothing
    .compose(ListFilter.create(item -> /* `item` is `Dummy` */)) 
    ...

Единственное отличие, которое я вижу между # 2 и # 3, - это ожидаемые подстановочные знаки для Transformer<T, R>:

  • _ # 2: Transformer<? super List<? extends Dummy>, ? extends R>
  • _ # 3: Transformer<? super List<capture of ? extends Dummy>, ? extends List<capture of ? extends Dummy>

Итак, есть несколько вопросов:

  1. Почему Object это тип item во 2-м случае (а не Dummy)?
  2. Почему Java не может определить тип возврата Transformer во 2-м случае?
  3. Как оператор map помогает с этим?
  4. Почему первый случай работает нормально?

1 Ответ

0 голосов
/ 16 июля 2018

Это потому, что компилятор не может перехватить подстановочный тип.

В первом случае вы можете попытаться добавить явный универсальный тип.И <Dummy>, и <Object> приведут к ошибке.Тип фактического генератора - (captrue#1 ?) extends Dummy, который определяется общим возвращаемым значением create.

Во втором случае ваш subject универсальный тип - List<? extends Dummy>.compose должен принимать Transformer<? super List<? extends Dummy>,? extends R>>, поэтому универсальный create должен быть ? extends Dummy (аналогично случаю 1).Но в текущем контексте компиляции (текущий оператор) тип группового символа не фиксируется.Компилятор не может определить универсальный тип, он просто использует Object, поэтому возникает ошибка.

В третьем случае map возвращает символ подстановки обратно.Вы можете попробовать любой метод с общим типом возврата Observable<R>, все они будут работать.Например, .flatMap(d -> Observable.just(d)).

Но обратите внимание, ваш случай 3 - это просто обходной путь.Рекомендуемое решение позволяет вашему универсальному ListFilter быть более гибким.

Вы должны определить его как ObservableTransformer<List<? extends T>, List<? extends T>>

class ListFilter<T> implements ObservableTransformer<List<? extends T>, List<? extends T>> {

  public static <T> ListFilter<T> create(Predicate<T> predicate) {
    return new ListFilter<>(predicate);
  }

  private final Predicate<T> predicate;

  private ListFilter(Predicate<T> predicate) {
    this.predicate = predicate;
  }

  @Override
  public ObservableSource<List<? extends T>> apply(Observable<List<? extends T>> upstream) {
    return upstream
        .flatMapSingle(list -> Observable.fromIterable(list)
            .filter(predicate::test)
            .toList());
  }
}
...