通用参数在流中返回List <childinterface>,但是直接方法调用返回List <parent>

时间:2017-01-06 05:24:18

标签: list generics lambda java-8 generic-list

对于设置,我有:

interface Parent

interface Child1 extends Parent

interface Child2 extends Parent

我在其他地方:

public class MyClass {
    private List<Child1> child1List = new ArrayList<>();

    public List<Parent> getChild1List(Contact contact) {
        return child1List.parallelStream()
                         .filter(m -> m.getContacts().contains(contact))
                         .sorted(Comparator.comparing(Parent::getParentField))
                         .collect(Collectors.toList());
    }
}

当我这样做时,getChild1List返回List<Parent>(不应该返回List<Child1>?)

后来,我发现该流对其他方法很有用,所以我提取它并用它构建了一个泛型方法。我有多个扩展Parent的接口,所以我做了如下:

    private <T extends Parent> List<T> returnsListByContact(List<T> childList, Contact contact) {
        return childList.parallelStream()
                        .filter(m -> m.getContacts().contains(contact))
                        .sorted(Comparator.comparing(Parent::getParentField))
                        .collect(Collectors.toList());
    }

getChild1List(Contact contact)成了:

    public List<Parent> getChild1List(Contact contact) {
        return returnsListByContact(child1List, contact);
    }

但现在它并不喜欢这样,引用getChild1List返回List<Child1>。我不明白为什么,因为流的实现根本没有改变 - 除了启动它的childList来自通用参数,而不是直接调用MyClass的私有成员字段。

那他们为什么要回归两件事?

1 个答案:

答案 0 :(得分:5)

(这个例子令人困惑。Meeting真的是Parent吗?)

getChild1List的第一个版本中,在collect(toList())上调用Stream<Child1>方法,其目标类型(由getChild1List的返回类型确定 - 是List<Parent>。这是有效的,因为允许T超类型的收集器收集类型为T的流。更具体地说,您要将类型为Child1的实例添加到List<Parent>类型 - 安全,是允许的。您也可以将getChild1List()的声明更改为返回List<Child1>而不是List<Parent>

您可以通过查看collect()Stream<T>的声明来查看允许差异的位置:

<R,A> R collect(Collector<? super T,A,R> collector)

? super T是允许差异的原因。

您对returnsListByContact

的声明
<T extends Parent> List<T> returnsListByContact(List<T> childList, ...)

允许差异。它采用List<T>类型的参数并返回List<T>。参数和返回类型必须相同。这就是为什么传入List<Child1>并尝试从返回类型为List<Parent>的方法返回它时不匹配的原因 - 这些类型不兼容。

要解决此问题,您需要在returnsListByContact声明中添加一些差异。我就是这样做的:

<T extends Parent> List<T> returnsListByContact(List<? extends T> childList, ...)

这允许您在传递某个子类型的列表时返回某种类型的列表,在这种情况下,在传入List<Parent>时返回List<Child1>,这是我认为您想要的。