首页 > 解决方案 > 将原始流收集到类型化集合中?

问题描述

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

最小的可重现示例

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

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

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

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

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

解决方法

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

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

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

我的搜索是否出现

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

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

我仍然收到Type mismatch: cannot convert from Object to List。怎么会?

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

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

背景:休眠5

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

关联

标签: javajava-streamtype-parametergeneric-collectionsraw-types

解决方案


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

Stream我调用的方法是这样声明的:

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

所以它返回一个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);

Java 11 上的输出:

class java.util.ArrayList
[Example]

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

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


推荐阅读