java - 将原始流收集到类型化集合中?
问题描述
我正在调用一个返回 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 返回一个类型化的流。我仍然觉得这个问题很有趣,可以发帖。
关联
- 在 Java 错误数据库中为 java.util.stream.Stream.map 方法转换内部 lambda 的问题
解决方案
提示就在 Java 错误记录中:一旦我使用原始类型,一切都会变得原始。Stream.collect()
也是一个泛型方法,所以它的原始版本返回 — Object
,不要感到惊讶。
Stream
我调用的方法是这样声明的:
<R,A> R collect(Collector<? super T,A,R> collector)
所以它返回一个R
,R
它可以从传递的收集器(无论是它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]
强制转换Stream
为Stream<?>
(隐式或显式)无需未经检查的操作即可摆脱原始类型。之后map()
可以按预期使用。而且没有必要@SuppressWarnings("unchecked")
。
这也意味着我原来的 Hibernate 场景的一个解决方案是在调用之前将Query
对象转换为 a而不仅仅是转换流。然后以与上述相同的方式将每个单独的对象转换为流操作中的a 。Query<?>
getResultStream()
map()
推荐阅读
- google-analytics - 谷歌标签管理器、Cookiebot 和谷歌分析:在标签中从“页面视图”切换到“窗口加载”跟踪类型的后果是什么?
- asp.net-core - 在 Razor 视图中填充 selectlistitem 时同步等待 NULL 引用异常
- java - 读取超过 9 万条记录的 excel 文件时出现内存不足异常
- mysql - 如何在mysql中使用union合并同一张表
- mysql - MYSQL 按日期分组并计算第一个日期
- python - 如何更改图例中的行数?
- php - 我想将数组 [1,2,3,4,5,6,7,8,9,10,11] 制作成数组 [1,2,3,4,5,6,7,8,9,1 ,0,1,1] 仅使用此算法
- vim - 长按键'j'后vim光标保持滚动
- android - 科尔多瓦插件火力库编译问题
- python - 如何在图像上添加文本(Python GUI PyQt5)