In this post we will learn how to perform grouping using new Java 8 Stream API. We will be working with the following list of students:
Let’s start by grouping students by country, this is fairly simple:
All we needed to do was to use
groupingBy collector from
groupingBy collector takes single parameter called
classifier that assigns grouping key
to every stream element.
In our example we used method reference
(which is equivalent to lambda expression
student -> student.getCountry()) to
groupingBy that we want to group students by country
(in other words country was our grouping key).
By default elements with the same key are gathered into
we may change this behaviour by specifying second parameter to
Here again we used method reference
ArrayList::new which is a shorter way
() -> new ArrayList().
Now you may start wondering how it works, actually
take any collector as a second argument. Diagram below illustrates how
the call to
groupingBy(classifier, collector) is executed:
As you can see on the diagram,
divides stream elements into groups according to values returned by
collector to get the final value for each group.
With our new
groupingBy knowledge we may start writing more
For example let’s count number of students per country,
code below does the job:
It works thanks to standard
counting() collector that just counts number of elements
passed to it.
And what about average student score per country? No problem with that:
averagingInt() collector that - you guess it - computes average of
ints passed to it (notice that it returns
One more example before we move forward, let’s compute max student age per country:
Here we do something more complex, we use
collector that transforms every element passed to it using
and then passes that transformed element to
So what we do here is that we first group students by country, then in every
group we map every student to his/her age and we pass that age to
that finally computes max age in every group.
That was something but what about this
Optional<Integer>s in the results?
maxBy() collector returns
Optional<T> to signify that sometimes it
cannot compute maximum e.g. it happens when we use
maxBy() on empty stream.
We may fix problem with optionals if we map
maxBy() result via
collectingAndThen() collector does exactly that:
Since we may pass any collector as a second argument to
we may pass another
groupingBy collector - this way we may group
stream elements by more than one criteria.
For example let’s group students by country and age:
That’s all for today, now go and write some code!