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)
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:
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.
Stream count() method in Java with exampleslong count() returns the count of elements in the stream. This is a special case of a reduction (A reduction operation takes a sequence of input elements and combines them into a single summary result by repeated application of a combining operation).
sum() The Stream API provides us with the mapToInt() intermediate operation, which converts our stream to an IntStream object. This method takes a mapper as a parameter, which it uses to do the conversion, then we can call the sum() method to calculate the sum of the stream's elements.
Collectors counting() method is used to count the number of elements passed in the stream as the parameter. It returns a Collector accepting elements of type T that counts the number of input elements. If no elements are present, the result is 0.
There are indeed several ways to do it. The one you haven't mentioned is .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.
Approach #2 relies on counting()
collector, which doesn't specify exactly how it should do the counting. The current implementation forwards to reducing
but that might change.
The summingInt
approach will accumulate the count in int
rather than Integer
and thus will not require any boxing/unboxing. It will be at its best if objects repeat a very large number of times.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With