将原始流收集到类型化集合中?

Collecting a raw stream into a typed collection?

我正在调用 return 原始 Stream 的库方法。我知道流中元素的类型,并希望收集到具有声明的元素类型的集合中。这样做的好处是什么,或者不是那么可怕?

最小可重现示例

为了一个可重现的例子,假设我想调用这个方法:

@SuppressWarnings("rawtypes")
static Stream getStream() {
    return Stream.of("Example");
}

我曾希望这会起作用,但我不明白为什么它不起作用:

    List<String> stringList = getStream().map(s -> (String) s).collect(Collectors.toList());

我得到 类型不匹配:无法从对象转换为列表。为什么?

解决方法

未经检查的演员表有效。为了缩小需要标记为故意未选中的位,我们可以这样做

    @SuppressWarnings("unchecked")
    Stream<String> stringStream = getStream();
    List<String> stringList = stringStream.collect(Collectors.toList());

在 Java 8 和 Java 11 上,returned 列表是 java.util.ArrayList,它包含预期的 String 元素。

我的搜索结果与否

我尝试在我的搜索引擎中搜索诸如 java 收集原始流 之类的术语。它并没有给我带来任何帮助。有一个已关闭的 Java 错误(link 在底部)提到一旦你对原始类型进行操作,一切都会变得原始。但是这个完全原始的版本也不起作用:

    List stringList = getStream().collect(Collectors.toList());

我仍然收到 类型不匹配:无法从对象转换为列表。怎么会?

我们正在为 Java 8 编码(还有一点时间)。

我知道这个问题有一些基于观点的东西。我仍然希望您能为我提供一些事实,帮助我编写通常被认为更好的代码。

背景:休眠 5

我想调用的方法是 org.hibernate.query.Query.getResultStream() 在原始 Query 上(Query 缺少类型参数)。我想获取流,因为我对要收集到的集合类型有特殊要求。在我的生产代码中,我使用的是 Collectors.toCollection()(不是本问题示例中的 Collectors.toLlist())。顺便说一句,在写这个问题时,我找到了一种方法来说服 Hibernate return 类型化流。我仍然觉得这个问题足够有趣 post。

Link

提示在 Java 错误记录中好吧:一旦我使用原始类型,一切都变得原始。 Stream.collect() 也是一个泛型方法,所以它的原始版本 returns — Object,不要惊讶。

我调用的Stream方法声明如下:

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

所以它 returns 一个 R,它可以从通过的收集器收集什么 R(无论是 Collectors.toList() 还是某些 Collectors.toCollection()) .一旦一切都变得原始,演绎就不再有效。和 collect() returns Object.

总而言之:泛型是好的。当我无法避免得到一些原始的东西时,尽早将它转换成它的通用对应物。

编辑: 感谢 Sweeper 和 Holger 在评论中提供的宝贵意见,这是我的首选解决方案:

    Stream<?> wildcardStream = getStream();
    List<String> stringList = wildcardStream.map(s -> (String) s)
            .collect(Collectors.toList());
    System.out.println(stringList.getClass());
    System.out.println(stringList);

Java11 上的输出:

class java.util.ArrayList
[Example]

Stream 转换为 Stream<?>(隐式或显式)无需未经检查的操作即可摆脱原始类型。之后 map() 可以按预期使用。而且不需要 @SuppressWarnings("unchecked").

这也意味着我最初的 Hibernate 方案的解决方案是在调用 getResultStream() 之前将 Query 对象 转换为 Query<?>而不仅仅是投射流。然后以与上述相同的方式在流操作中将每个单独的对象转换为map()