流中的类型擦除

时间:2019-06-04 15:21:56

标签: java generics java-stream type-inference type-erasure

我不是Java 8的新手,我知道流是非常强大,便捷的数据处理方式,而且我经常使用它们。实际上,我使用流进行了更多的复杂数据处理,没有任何问题,但是看看吗?看起来很基本的处理,但是类型擦除存在问题。为什么它不能处理这样的数据收集?

Set[] arrOfSets = {new TreeSet<>(List.of(1, 2)), new LinkedHashSet<>(Arrays.asList(1, 2, 3, null))};

/*why type erasure wins here? */
List<Number> collect = (List<Number>) Arrays.stream(arrOfSets).flatMap(Set::Stream).collect(Collectors.toList());

Object collect2 = Arrays.stream(arrOfSets).flatMap(set -> set.stream()).collect(Collectors.toList());
System.out.println("Collect2:" + collect2); /*[1, 2, 1, 2, 3, null]*/

/*Here type interference works fine*/
List<Integer> collect1 = new TreeSet<>(Arrays.asList(1, 2, 3)).stream().collect(Collectors.toList());

System.out.println(collect2.getClass().getSimpleName()); //ArrayList

List<Set>相同:

List<?> collect3 = listOfSets.stream().flatMap(Set::stream).collect(Collectors.toList());

运行时异常:java:不兼容的类型:java.lang.Object无法转换为java.util.List

我觉得这是河流的巨大缺点。在将来的sdk中是否有任何机会改善Streams API中的类型干扰,或者没有办法解决该问题?

1 个答案:

答案 0 :(得分:1)

问题是您使用的是没有通用类型的原始Set[]

要使代码正常工作,您应该使用通用数组:

Set<Number>[] arrOfSets = new Set[]{
        new TreeSet<>(List.of(1, 2)), 
        new LinkedHashSet<>(Arrays.asList(1, 2, 3, null))
};
List<Number> collect = Arrays.stream(arrOfSets) // Stream<Set<Number>>
        .flatMap(Set::stream) // Stream<Number>
        .collect(Collectors.toList());

或使用Stream<Object>将流从Stream<Number>投射到Stream.map()

Set[] arrOfSets = new Set[]{
        new TreeSet<>(List.of(1, 2)), 
        new LinkedHashSet<>(Arrays.asList(1, 2, 3, null))
};
List<Number> collect = Arrays.stream(arrOfSets) // Stream<Set>
        .map(i -> (Set<Number>) i) // Stream<Set<Number>>
        .flatMap(Set::stream) // Stream<Object>
        .collect(Collectors.toList());

正如您已经提到的,List<Set>的问题相同。 Set没有类型,因此像以前一样使用List<Set<Number>>或强制类型转换。 我建议使用键入的ListSet