我有一个Cat类,它有String name和int tailLength字段以及String getName()和int getTailLength()方法。Cat实例放置在List<Cat> cats中。我的问题是:
为什么这样做很好:
int tailsEndToEnd = cats.stream().collect(Collectors.summingInt(Cat::getTailLength); //(1)
但这并不意味着:
String allNames = cats.stream().collect(Collectors.joining(Cat::getName); //(2)
我知道我可以像这样收集猫的名字:
cats.stream().collect(Collectors.mapping(Cat::getName, joining(", ")); //(3),
只是好奇为什么(2)不工作,看到它完全类似于(1),不管输出是什么样子(没有逗号,等等)。
谢谢
发布于 2022-01-09 14:36:47
所有Collector.joining变体都返回一个Collector<CharSequence, ?, String>,这意味着它们只能在Stream<CharSequence>上操作。
当您使用Collectors.mapping(Cat::getName,joining(", "));时,mapping将您的Stream<Cat>转换为Stream<CharSequence>,这允许joining()处理该Stream。
您不能使用Stream<Cat>直接处理joining,因为它没有接受映射函数将Cat转换为String的变体。joining的所有参数都是CharSequences,用作分隔符、前缀或后缀。
这与summingInt不同,后者接受ToIntFunction<? super T>映射函数将Stream的元素映射到int。
发布于 2022-01-09 14:43:58
Eran的回答基本上概括了这一点,我只想补充一下,在你的具体情况下,一个更地道(当然更容易理解)的方式来实现你想要的是:
String catNames = cats.stream().map(Cat::getName).collect(Collectors.joining());通过这种方式,每个操作都可以独立地进行检查,因此易于阅读和理解:
而在您的第三个示例中,您在collect中执行这两个操作,这不太容易阅读。
发布于 2022-01-10 13:06:12
我还没有看到的是,接受一个参数的Collectors.joining方法只接受一个CharSequence作为一个论点:
公共静态…连接(CharSequence分隔符)
(这里重要的不是返回类型,而是方法参数定义。)
Cat::getName不是一个CharSequence,它是一个方法引用(可以解释为一个函数)。对这种方法来说,这永远不是一个合适的论据。
正如其他人所说的,您需要首先映射到一个字符串,然后调用Collections.joining,要么使用零参数,要么使用单个分隔符参数。
https://stackoverflow.com/questions/70642237
复制相似问题