如何按实例获取列表的所有元素?

时间:2015-03-30 08:28:46

标签: java generics collections java-8 java-stream

如何按实例获取列表的所有元素?

我有一个列表,可以有接口Foo的任何类实现:

interface Foo;
class Bar implements Foo;

我想使用java8 stream api提供一个实用工具方法来提取特定类类型的所有元素:

public static <T extends Foo> List<T> getFromList(List<Foo> list, Class<T> type) {
    return (List<T>) list.stream().filter(entry -> type.isInstance(entry)).collect(Collectors.toList());
}

使用:

List<Foo> list;
List<Bar> bars = Util.getFromList(list, Bar.class);

结果:它有效,但由于@SuppressWarnings的{​​{1}},我必须添加unchecked cast。我怎么能避免这个?

3 个答案:

答案 0 :(得分:5)

引入另一个扩展S的类型参数是正确的,但是,为了将结果设为List<S>,而不是List<T>,您必须.map()type::isInstance谓词传递给S的条目。

public static <T extends Foo, S extends T> List<S> getFromList(List<T> list, Class<S> type) {
    return list.stream()
               .filter(type::isInstance)
               .map(type::cast)
               .collect(Collectors.toList());
}

正如@Eran所建议的那样,这甚至可以简化为只使用一个类型参数:

public static <T extends Foo> List<T> getFromList(List<Foo> list, Class<T> type) {
    return list.stream()
               .filter(type::isInstance)
               .map(type::cast)
               .collect(Collectors.toList());
}

答案 1 :(得分:4)

这似乎没有任何警告:

public static <T extends Foo> List<T> getFromList(List<Foo> list, Class<T> type) {
    return list.stream()
               .filter(entry -> type.isInstance(entry))
               .map(entry->type.cast(entry))
               .collect(Collectors.toList());
}

使用Number替换Foo和Integer替换Bar:

public static <T extends Number> List<T> getFromList(List<Number> list, Class<T> type) {
    return list.stream().filter(entry -> type.isInstance(entry)).map(entry->type.cast(entry)).collect(Collectors.toList());
}

public static void main(String[] args)
{
    List<Number> list = new ArrayList<>();
    list.add(5);
    list.add(3.4);
    list.add(7);
    List<Integer> bars = getFromList(list, Integer.class);
    System.out.println(bars);
}

输出:

[5, 7]

答案 2 :(得分:1)

由于listtype的类型不同,而是在继承层次关系中,您可能会添加另一个类似于以下类型的参数:

public static <T extends Foo, S extends T> List<T> getFromList(List<T> list, Class<S> type) {
    return list.stream().filter(type::isInstance).collect(Collectors.toList());
}