In this short tutorial, we'll see how we can group equal objects and count their occurrences in Java. We'll use the groupingBy() collector in Java.
2. Count Occurrences using Collectors.groupingBy()
Collectors.groupingBy() provides functionality similar to the GROUP BY clause in SQL. We can use this to group objects by any attribute and store results in a Map.
For instance, let's consider a scenario where we need to group equal Strings in a stream and count their occurrences:
List<String> list = new ArrayList<>(Arrays.asList("Foo", "Bar", "Bar", "Bar", "Foo"));
We can group equal Strings, which in this case would be “Foo” and “Bar”. The result Map will store these Strings as keys. The values for these keys will be the count of occurrences. The value for “Foo” will be 2 and “Bar” will be 3:
Map<String, Long> result = list.stream() .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); Assert.assertEquals(new Long(2), result.get("Foo")); Assert.assertEquals(new Long(3), result.get("Bar"));
Let's decode the above code snippet:
- Map<String, Long> result – this is the output result Map that will store the grouped elements as keys and count their occurrences as values
- list.stream() – we convert the list elements into Java stream to process the collection in a declarative way
- Collectors.groupingBy() – this is the method of Collectors class to group objects by some property and store results in a Map instance
- Function.identity() – it is a functional interface in Java; the identity method returns a Function that always returns its input arguments
- Collectors.counting() – this Collectors class method counts the number of elements passed in the stream as a parameter
We could use Collectors.groupingByConcurrent() instead of Collectors.groupingBy(). It also performs group by operation on input stream elements. The method collects the results in ConcurrentMap, thus improving efficiency.
For example, for the input list:
List<String> list = new ArrayList<>(Arrays.asList("Adam", "Bill", "Jack", "Joe", "Ian"));
We can group equal length Strings using Collectors.groupingByConcurrent():
Map<Integer, Long> result = list.stream() .collect(Collectors.groupingByConcurrent(String::length, Collectors.counting())); Assert.assertEquals(new Long(2), result.get(3)); Assert.assertEquals(new Long(3), result.get(4));
In this article, we covered the usage of Collector.groupingBy() to group the equal objects.
And to wrap up, you'll find the source code to this article over on GitHub.