Data collection is simplified in Java 8 syntax very much. you only need to point out "the expected result " not to worry about how to collect. In Java 8 , there exist a factory class "Collectors", let't see how it applies.
Math Problems
long howManyDishes = menu.stream().collect(Collectors.counting()); // == long howManyDishes2 = menu.stream().count(); Comparator<Dish> dishCaloriesComparator = Comparator.comparingInt(Dish::getCalories); Optional<Dish> mostCalorieDish = menu.stream() .collect(Collectors.maxBy(dishCaloriesComparator)); // get object with max calories // get the total calories int totalCalories = menu.stream().collect(Collectors.summingInt(Dish::getCalories)); // get the average calories double avgCalories = menu.stream().collect(Collectors.averagingInt(Dish::getCalories)); // get total, average, max, min IntSummaryStatistics menuStatistics = menu.stream().collect(
Collectors.summarizingInt(Dish::getCalories));
String Concatenation
String shortMenu = menu.stream().map(Dish::getName).collect(Collectors.joining(", "));
Reduce
// get total calories in reduing way int totalCalories2 = menu.stream().collect(Collectors.reducing(0, Dish::getCalories,
(i, j) -> i + j)); // get the max calories Optional<Dish> mostCalorieDish2 = menu.stream().collect(Collectors.reducing( (d1, d2) -> d1.getCalories() > d2.getCalories() ? d1 : d2)); // self-implement toList collector Stream<Integer> stream = Arrays.asList(1, 2, 3, 4, 5, 6).stream(); List<Integer> numbers = stream.reduce(new ArrayList<Integer>(), // init value (List<Integer> l, Integer e) -> { l.add(e);return l; }, // process (List<Integer> l1, List<Integer> l2) -> {
l1.addAll(l2);return l1; }); // final process // total calories int totalCalories3 = menu.stream().collect(Collectors.reducing(0,Dish::getCalories,
Integer::sum)); int totalCalories4 = menu.stream().mapToInt(Dish::getCalories).sum(); // old way
Group By
Group by is like SQL group by statement., you can do nexted grouping , criteria grouping ...// group by type , type is an enum Map<Dish.Type, List<Dish>> dishesByType = menu.stream().collect(
Collectors.groupingBy(Dish::getType)); // criteria grouping Map<CaloricLevel, List<Dish>> dishesByCaloricLevel = menu.stream().collect( Collectors.groupingBy(dish -> { if (dish.getCalories() <= 400) { return CaloricLevel.DIET; } else if (dish.getCalories() <= 700) { return CaloricLevel.NORMAL; }else { return CaloricLevel.FAT; }})); // nested grouping Map<Dish.Type, Map<CaloricLevel, List<Dish>>> dishesByTypeCaloricLevel =
menu.stream().collect( Collectors.groupingBy(Dish::getType, // 1st grouping Collectors.groupingBy(dish -> { // 2ed grouping if (dish.getCalories() <= 400) return CaloricLevel.DIET; else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL; else return CaloricLevel.FAT; }))); // collecting data with grouping // result is : {MEAT=3, FISH=2, OTHER=4} Map<Dish.Type, Long> typesCount = menu.stream().collect(
Collectors.groupingBy(Dish::getType, Collectors.counting())); // get the max calories of each group , group by type //result is : {FISH=Optional[salmon], OTHER=Optional[pizza], MEAT=Optional[pork]} Map<Dish.Type, Optional<Dish>> mostCaloricByType = menu.stream().collect(
Collectors.groupingBy(Dish::getType, Collectors.maxBy(Comparator.comparingInt(Dish::getCalories)))); // get the max colories of each group , retrive value of each optional from above //result is {FISH=salmon, OTHER=pizza, MEAT=pork} Map<Dish.Type, Dish> mostCaloricByType2 = menu.stream().collect(
Collectors.groupingBy(Dish::getType, // group by type Collectors.collectingAndThen(Collectors.maxBy(
Comparator.comparingInt(Dish::getCalories)), //transformed Collector
Optional::get))); // function of transfering // grouping by can pass in 2 params , the second param will apply to all elements of each group. Map<Dish.Type, Integer> totalCaloriesByType = menu.stream().collect(
Collectors.groupingBy(Dish::getType, Collectors.summingInt(Dish::getCalories))); // get all caloricLevels of each Dish Type // Collectors.mapping is powerful like map() Map<Dish.Type, Set<CaloricLevel>> caloricLevelsByType = menu.stream().collect( Collectors.groupingBy(Dish::getType, Collectors.mapping( dish -> { if (dish.getCalories() <= 400) { return CaloricLevel.DIET; } else if (dish.getCalories() <= 700) { return CaloricLevel.NORMAL; } else { return CaloricLevel.FAT; }},Collectors.toSet()))); // point out which kind of set you want to use Map<Dish.Type, Set<CaloricLevel>> caloricLevelsByType2 = menu.stream().collect( Collectors.groupingBy(Dish::getType, Collectors.mapping( dish -> { if (dish.getCalories() <= 400) { return CaloricLevel.DIET; } else if (dish.getCalories() <= 700) { return CaloricLevel.NORMAL; } else { return CaloricLevel.FAT; }},Collectors.toCollection(HashSet::new))));
Partition By
Partion By is similar to Group by but the input parameter is limited to "Predicate".//{false=[pork, beef, chicken, prawns, salmon], //true=[french fries, rice, season fruit, pizza]} Map<Boolean, List<Dish>> partitionedMenu = menu.stream().collect(Collectors.partitioningBy(Dish::isVegetarian)); List<Dish> vegetarianDishes = partitionedMenu.get(true); // to retrive values // == List<Dish> vegetarianDishes2 = menu.stream().filter(Dish::isVegetarian).collect(
Collectors.toList()); // nexted partioning & grouping , producing a 2 level grouping //{false={FISH=[prawns, salmon], MEAT=[pork, beef, chicken]}, // true={OTHER=[french fries, rice, season fruit, pizza]}} Map<Boolean, Map<Dish.Type, List<Dish>>> vegetarianDishesByType = menu.stream().collect( Collectors.partitioningBy(Dish::isVegetarian, Collectors.groupingBy(Dish::getType)));
// getType is not predicate so use group by
No comments:
Post a Comment