RxJava的意外类型推断

时间:2018-06-13 10:28:50

标签: java generics collections rx-java rx-java2

我有一个常见的Transformer,只需使用给定的Predicate过滤列表:

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的类型(而不是Dummy)?
  2. 为什么Java不能在第二种情况下推断出Transformer的返回类型?
  3. map运营商如何帮助它?
  4. 为什么第一种情况正常?

1 个答案:

答案 0 :(得分:0)

这是因为编译器无法重新捕获通配符类型。

在第一种情况下,您可以尝试添加显式泛型。 <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());
  }
}