Here's some examples of various ways we can collect Data with streams
GIVEN : A Menu which contains a list of Dishes
Listmenu = Arrays.asList( new Dish("pork", false, 800, Dish.Type.MEAT), new Dish("beef", false, 700, Dish.Type.MEAT), new Dish("chicken", false, 400, Dish.Type.MEAT), new Dish("french fries", true, 530, Dish.Type.OTHER), new Dish("rice", true, 350, Dish.Type.OTHER), new Dish("season fruit", true, 120, Dish.Type.OTHER), new Dish("pizza", true, 550, Dish.Type.OTHER), new Dish("prawns", false, 300, Dish.Type.FISH), new Dish("salmon", false, 450, Dish.Type.FISH)); Dish(String name, boolean vegetarian, int calories, Type type)
Count the number of Dishes:
menu.stream().count() menu.stream().collect(Collectors.counting())
Finding maximum and minimum in a Stream of values
OptionalSummarization - the below methods are avaialble in Collectors for Summarization Collectors.summingInt Collectors.summingLong Collectors.summingDoublehighCalorieDish = menu.stream() .collect(Collectors.maxBy(Comparator.comparingInt(Dish::getCalories)));
We also have equivalent for average Collectors.averagingInt/averagingLong/averagingDouble
int totalCalories = menu.stream().collect(Collectors.summingInt(Dish::getCalories)); double avgCalories = menu.stream().collect(averagingInt(Dish::getCalories));
This Collector gathers all that information in a class called IntSummaryStatistics
IntSummaryStatistics menuStatistics = menu.stream().collect(summarizingInt(Dish::getCalories)); IntSummaryStatistics{count=9, sum=4300, min=120,average=477.777778, max=800}
Joining Strings -Collector which reduces a Stream to a single result doesn’t operate on
numeric values but allows a concatenation of Strings
String shortMenu = menu.stream().map(Dish::getName).collect(joining(", "));
Generalized summarization with reduction - Collectors.reducing factory method is a generalization of all of the above specialized cases.
int totalCalories = menu.stream().collect(reducing(0, Dish::getCalories, (Integer i, Integer j) -> i + j)); OptionalmostCalorificDish =menu.stream().collect(reducing((d1, d2) -> d1.getCalories() > d2.getCalories() ? d1 : d2));
Various ways to find the total number of calories in the menu:
Using Data Processing way :
System.out.println("Using Data Processing way ...with reduce " + menu.stream().map(Dish::getCalories).reduce(0, Integer::sum)); System.out.println("Using Data Processing way ..." + menu.stream().mapToInt(Dish::getCalories).sum());
Using Data Collecting way
System.out.println("Using Data Collecting way ..." + menu.stream().collect(summingInt(Dish::getCalories))); System.out.println("Using Data Collecting way with reduction..." + menu.stream().collect(reducing(0, Dish::getCalories, Integer::sum)));Grouping - Group the dishes based on the type using Collectors.groupingBy factory method
Map<Dish.Type, List<Dish>> dishesByType = menu.stream().collect(groupingBy(Dish::getType)); { FISH=[prawns, salmon], OTHER=[french fries, rice, season fruit, pizza], MEAT=[pork, beef, chicken] }Here, you pass to the groupingBy method a Function extracting the corresponding Dish.Type for each Dish in the Stream. We call this Function a classification function because it’s used to classify the elements of the Stream in different groups.
Complex Classification Ex -
classify as “diet” all dishes with 400 calories or fewer,
set to “normal” the dishes having between 400 and 700 calories, and
set to “fat” the ones with more than 700 calories.
public enum CaloricLevel {DIET, NORMAL, FAT} Map<CaloricLevel, List<Dish>> dishMap = menu.stream() .collect(groupingBy( dish -> { if (dish.getCalories() <= 400) return Dish.CaloricLevel.DIET; else if (dish.getCalories() <= 700) return Dish.CaloricLevel.NORMAL; else return Dish.CaloricLevel.FAT; } ));
Collecting data in subgroups
1. count the number of dishes for each type
Map<Dish.Type, Long> numberOfDishesByType = menu.stream() .collect(groupingBy( Dish::getType, Collectors.counting() ));
2. retrieves total calories of each Dish type
Map<Dish.Type, Integer> integerMap = menu.stream() .collect( Collectors.groupingBy( Dish::getType, Collectors.reducing(0, Dish::getCalories, (a, b) -> a + b) ) ); Map<Dish.Type, Integer> totalCaloriesByType = menu.stream() .collect( groupingBy( Dish::getType, summingInt(Dish::getCalories) ) );
3. Calories available in the menu for each type of dish
Map<Dish.Type, List<Integer>> typeListMap = menu.stream() .collect( groupingBy( Dish::getType, mapping( Dish::getCalories, toList() ) ) ); { FISH=[300, 450], OTHER=[530, 350, 120, 550], MEAT=[800, 700, 400] }