Below is an example of using a Collector to make a Map whose keys are currencies and whose values are lists of transactions with corresponding currencies
Like the groupingBymethod, Collectors provide many pre-defined advanced reduction methods.
Methods that reduce and summarize the elements from the stream into a single value
Grouping elements from the stream
Partitioning elements from the stream
Reducing and Summarizing
Finding Maximum and Minimum Values
Collectors.maxBy and Collectors.minBy methods take a Comparator as argument to compare the elements in the stream
This is one of the advantages of using stream and Collectors. Collectors.maxBy(Comparator) is easy to understand - we are getting the maximum value from the stream by the comparator we put in.
Collectors.summingInt and Collectors.averagingInt accept a function that maps an object into int, and return a Collector which will perform the requested operation when passed into collectmethod.
int totalCals = menu.stream()
.collect(summingInt(Dish::getCalories));
summingInt collector (Modern Java in Action)
We can also use Collectors.summarizingInt which will return IntSummaryStatistics containing all the statistics about the given integers.
Collectors.reducing method is a generalized version of reducing.
First argument: initial value of the reduction process
Second argument: Method to transform element into target data type
Third argument: BinaryOperator that aggregates 2 items into a single value of the same type
One argument version is a special type where the first argument (initial value) is the first item of the string and the second argument is an identity function.
// Three arguments version
int totalAge = people.stream().collect(reducing(
0, Person::getAge, (a1, a2) -> a1 + a2));
// One argument version
Optional<Person> oldestPerson = people.stream()
.collect(reducing(
(p1, p2) -> p1.getAge() > p2.getAge() ? p1: p2));
Grouping
We can easily group elements of a stream into a set or a list based on one or more properties.
We pass a classification function to groupingBymethod
We can move the filtering predicate inside the collectmethod as a second predicate - in this case, keys that do not have any element will still appear in the resulting map.
Many times we will have Optionalin the resulting map depending on which filtering or mapping method we use.
To remove this Optional, or more generally to adapt the result returned by a collector into a different type, we can use Collectors.collectingAndThen method.
Collectors.collectingAndThen has 2 arguments - the first is the collector and the second is a transformation function.
Nested collectors (Modern Java in Action)
We have the outermost groupingBycollector denoted as a blue dashed box.
The groupingBycollector wraps the three collectingAndThencollectors, so that the result of those can be collected again with the groupingBycollector.
collectingAndThencollector wraps the maxBycollector, and the result of the maxBycollector is transformed by Optional::get method.
Partitioning
Partitioning is a special case of grouping where a predicate is used as a classification function
Since predicates return a Boolean, the resulting grouping Map will have at most 2 keys, which are Boolean.
Map<Boolean, List<Dish>> partitionedMenu = menu.stream()
.collect(partitioningBy(Dish::isVegetarian));
// isVegeterian is a partitioning function (predicate)
Advantages of Partitioning
It is easier and more intuitive to use partitioning when you want to separate a stream into two lists.
List<Dish> vegetarianDishes = menu.stream()
.collect(partitioningBy(Dish::isVegeterian))
.get(true);
// since the resulting grouping of collect is a map with true and false being keys
We can also apply multi-level mapping by using an overloaded version of partitioningBymethod.
Map<Boolean, Map<Dish.Type, List<Dish>>> vegetarianDishesByType = menu.stream()
.collect(partitioningBy(Dish::isVegetarian, groupingBy(Dish::getType)));
// result will be something like
// {true = {OTHER=[Salad, Fruit]}, false = {FISH=[salmon], MEAT=[pork]}}
Main Static Factory methods of the CollectorsClass