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

Ole*_*.V. 0 java raw-types generic-collections type-parameter java-stream

我正在调用一个返回 raw 的库方法Stream。我知道流中元素的类型,并希望将其收集到具有声明元素类型的集合中。什么是好的或不那么骇人听闻的做法?

最小的可重复示例

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

@SuppressWarnings("rawtypes")
static Stream getStream() {
    return Stream.of("Example");
}
Run Code Online (Sandbox Code Playgroud)

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

    List<String> stringList = getStream().map(s -> (String) s).collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

我得到Type mismatch: cannot convert from Object to List。为什么?

解决方法

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

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

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

我的搜索结果出现与否

我尝试使用我的搜索引擎搜索诸如java collect raw stream 之类的术语。它没有让我找到任何有用的东西。有一个封闭的 Java 错误(底部的链接)提到一旦您对原始类型进行操作,一切都会变得原始。但是这个完全原始的版本也不起作用:

    List stringList = getStream().collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

我仍然遇到Type mismatch: cannot convert from Object to List。怎么来的?

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

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

背景:Hibernate 5

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

关联

Ole*_*.V. 5

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

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

    <R,A> R collect?(Collector<? super T,A,R> collector)
Run Code Online (Sandbox Code Playgroud)

所以它返回一个RR它可以从传递的收集器(无论是它Collectors.toList()还是一些Collectors.toCollection())收集什么。一旦一切都变得原始,演绎就不再有效。并collect()返回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);
Run Code Online (Sandbox Code Playgroud)

Java 11 上的输出:

class java.util.ArrayList
[Example]
Run Code Online (Sandbox Code Playgroud)

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

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