java 计算流的元素

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30451284/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 17:08:30  来源:igfitidea点击:

Counting elements of a Stream

javacountjava-8java-streamcollectors

提问by principal-ideal-domain

I want to count the different elements of a stream and am wondering why

我想计算流的不同元素,想知道为什么

Stream<String> stream = Stream.of("a", "b", "a", "c", "c", "a", "a", "d");
Map<String, Integer> counter1 = stream.collect(Collectors.toMap(s -> s, 1, Integer::sum));

doesn't work. Eclipse tells me

不起作用。日食告诉我

The method toMap(Function, Function, BinaryOperator) in the type Collectors is not applicable for the arguments (( s) -> {}, int, Integer::sum)

Collectors 类型中的 toMap(Function, Function, BinaryOperator) 方法不适用于参数 (( s) -> {}, int, Integer::sum)

By the way, I know about that solution:

顺便说一句,我知道该解决方案:

Map<String, Long> counter2 = stream.collect(Collectors.groupingBy(s -> s, Collectors.counting()));

So I have two questions:

所以我有两个问题:

  1. What is the mistake in my first approach?
  2. How would you implement such a counter?
  1. 我的第一种方法有什么错误?
  2. 你将如何实现这样的计数器?

EDIT:I solved the first question by myself:

编辑:我自己解决了第一个问题:

Map<String, Integer> counter1 = stream.collect(Collectors.toMap(s -> s, s -> 1, Integer::sum)); 

Java is expecting a function as second argument.

Java 期待一个函数作为第二个参数。

回答by Misha

There are indeed several ways to do it. The one you haven't mentioned is .collect(groupingBy(x -> x, summingInt(x -> 1)));

确实有几种方法可以做到。你没有提到的是.collect(groupingBy(x -> x, summingInt(x -> 1)));

There are some differences in performance.

性能上存在一些差异。

Approach #1 is going to be at its best if there are very few objects per bucket. In the ideal case of only 1 object per bucket, you end up with the final map right away with no need to modify the entries. In the worst case of having a very large number of repeated objects, it will have to do a lot of boxing/unboxing.

如果每个存储桶的对象很少,则方法 #1 将处于最佳状态。在每个存储桶只有 1 个对象的理想情况下,您可以立即获得最终映射,无需修改条目。在拥有大量重复对象的最坏情况下,它将不得不进行大量装箱/拆箱。

Approach #2 relies on counting()collector, which doesn't specify exactly how it should do the counting. The current implementation forwards to reducingbut that might change.

方法#2 依赖于counting()收集器,它没有具体说明它应该如何进行计数。当前的实现向前推进,reducing但这可能会改变。

The summingIntapproach will accumulate the count in intrather than Integerand thus will not require any boxing/unboxing. It will be at its best if objects repeat a very large number of times.

summingInt方法将在int而不是累积计数Integer,因此不需要任何装箱/拆箱。如果对象重复非常多的次数,这将是最好的。

As for which one to choose, it is best to code for clarity and optimize when it becomes necessary. To me, groupingBy(x->x, counting())expresses the intent most clearly, so that's the one I would favor.

至于选择哪一个,最好编码清晰,必要时优化。对我来说,groupingBy(x->x, counting())最清楚地表达了意图,所以这是我最喜欢的。

回答by Roland

The following should work if you are not using parallel streams:

如果您不使用并行流,以下应该有效:

final int[] counter = {0};
stream.peek(s -> counter[0]++);