为了获得Java新流的一些经验,我一直在开发用于处理纸牌的框架。这是我的代码的第一个版本,该代码用于创建Map,其中包含手中的每套西装的张数(Suitenum):

Map<Suit, Long> countBySuit = contents.stream() // contents is ArrayList<Card>
        .collect( Collectors.groupingBy( Card::getSuit, Collectors.counting() ));

这很好,我很高兴。然后,我进行了重构,为“Suit Cards”和Jokers创建了单独的Card子类。因此,由于Jokers没有合适的衣服,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() ) );

请注意,巧妙地插入了过滤器,以确保所考虑的卡实际上是西装卡,而不是 clown 卡。但这不起作用!显然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() ) );

我不知道强制类型转换被视为可执行语句。为什么这样做?为何编译器需要这样做?

最佳答案

请记住,filter操作不会更改Stream元素的编译时类型。是的,从逻辑上讲,我们可以看到,超过这一点的所有内容都将是SuitCardfilter所看到的只是Predicate。如果该谓词稍后更改,则可能导致其他编译时问题。

如果要将其更改为Stream<SuitCard>,则需要添加一个为您执行强制转换的映射器:

Map<Suit, Long> countBySuit = contents.stream() // Stream<Card>
    .filter( card -> card instanceof SuitCard ) // still Stream<Card>, as filter does not change the type
    .map( SuitCard.class::cast ) // now a Stream<SuitCard>
    .collect( Collectors.groupingBy( SuitCard::getSuit, Collectors.counting() ) );

详细信息请引用Javadoc

10-06 14:33