Counting Stream Elements

I want to calculate different elements of a flow and I wonder 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)); 

does not work. Eclipse tells me

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

By the way, I know about this solution:

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

I have two questions:

  • What is the mistake in my first approach?
  • How would you implement such a counter?

EDIT: I solved the first question myself:

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

Java expects a function as a second argument.

+7
java java-8 count java-stream collectors
source share
1 answer

There are really several ways to do this. The one you did not mention is .collect(groupingBy(x -> x, summingInt(x -> 1)));

There are some performance differences.

Approach No. 1 will be at best if there are very few objects on the bucket. In the ideal case, for only 1 object per bucket, you get the final map right away, without having to change the entries. In the worst case, with a very large number of repeating objects, he will have to do a lot of boxing / unpacking.

Approach # 2 depends on the counting() collector, which does not indicate exactly how it should do the counting. The current implementation switches to reducing , but this may change.

The summingInt approach will accumulate the counter in int , not Integer and, therefore, will not require any boxing / unpacking. This will be at best if the objects are repeated so many times.

As for the choice, it is best to make code for clarity and optimization when it becomes necessary. For me, groupingBy(x->x, counting()) expresses the intention most clearly, so the one I would approve of.

+4
source share

All Articles