为了获得一些使用 Java 的新流的经验,我一直在开发一个处理扑克牌的框架。这是我创建 Map
的代码的第一个版本,其中包含手中每套花色的牌数( Suit
是 enum
):
Map<Suit, Long> countBySuit = contents.stream() // contents is ArrayList<Card>
.collect( Collectors.groupingBy( Card::getSuit, Collectors.counting() ));
这很好用,我很高兴。然后我重构,为“Suit Cards”和 Jokers 创建单独的 Card 子类。所以 getSuit()
方法从 Card
类移动到它的子类 SuitCard
,因为小丑没有西装。新代码:
Map<Suit, Long> countBySuit = contents.stream() // contents is ArrayList<Card>
.filter( card -> card instanceof SuitCard ) // reject Jokers
.collect( Collectors.groupingBy( SuitCard::getSuit, Collectors.counting() ) );
请注意过滤器的巧妙插入,以确保所考虑的卡片实际上是花色卡片而不是小丑。但它不起作用!显然 collect
行没有意识到它传递的对象保证是 SuitCard
。
在对此困惑了好一阵子之后,无奈之下我尝试插入一个 map
函数调用,令人惊讶的是它成功了!
Map<Suit, Long> countBySuit = contents.stream() // contents is ArrayList<Card>
.filter( card -> card instanceof SuitCard ) // reject Jokers
.map( card -> (SuitCard)card ) // worked to get rid of error message on next line
.collect( Collectors.groupingBy( SuitCard::getSuit, Collectors.counting() ) );
我不知道转换类型被认为是可执行语句。为什么这行得通?为什么编译器需要它?
原文由 Robert Lewis 发布,翻译遵循 CC BY-SA 4.0 许可协议
请记住
filter
操作不会更改Stream
的元素的编译时类型。是的,从逻辑上讲,我们看到通过这一点的所有内容都是SuitCard
,所有filter
看到的都是Predicate
如果该谓词稍后更改,则可能会导致其他编译时问题。如果您想将其更改为
Stream<SuitCard>
,您需要添加一个映射器来为您进行转换:我建议您参阅 Javadoc 以获取完整的详细信息。