/* * Copyright 2005 JBoss Inc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package lambdasinaction.dsl; import lambdasinaction.chap6.Dish; import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.stream.Collector; import static java.util.stream.Collectors.groupingBy; import static lambdasinaction.chap6.Dish.menu; import static lambdasinaction.dsl.Grouping.GroupingBuilder.groupOn; public class Grouping { enum CaloricLevel { DIET, NORMAL, FAT }; public static void main(String ... args) { System.out.println("Dishes grouped by type and caloric level: " + groupDishedByTypeAndCaloricLevel2()); System.out.println("Dishes grouped by type and caloric level: " + groupDishedByTypeAndCaloricLevel3()); } private static CaloricLevel getCaloricLevel( Dish dish ) { if (dish.getCalories() <= 400) return CaloricLevel.DIET; else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL; else return CaloricLevel.FAT; } private static Map<Dish.Type, Map<CaloricLevel, List<Dish>>> groupDishedByTypeAndCaloricLevel2() { return menu.stream().collect( twoLevelGroupingBy(Dish::getType, dish -> getCaloricLevel( dish ) ) ); } public static <A, B, T> Collector<T, ?, Map<A, Map<B, List<T>>>> twoLevelGroupingBy(Function<? super T, ? extends A> f1, Function<? super T, ? extends B> f2) { return groupingBy(f1, groupingBy(f2)); } private static Map<Dish.Type, Map<CaloricLevel, List<Dish>>> groupDishedByTypeAndCaloricLevel3() { Collector<? super Dish, ?, Map<Dish.Type, Map<CaloricLevel, List<Dish>>>> c = groupOn( ( Dish dish ) -> getCaloricLevel( dish ) ).after( Dish::getType ).get(); return menu.stream().collect( c ); } public static class GroupingBuilder<T, D, K> { private final Collector<? super T, ?, Map<K, D>> collector; public GroupingBuilder( Collector<? super T, ?, Map<K, D>> collector ) { this.collector = collector; } public Collector<? super T, ?, Map<K, D>> get() { return collector; } public <J> GroupingBuilder<T, Map<K, D>, J> after(Function<? super T, ? extends J> classifier) { return new GroupingBuilder<>( groupingBy( classifier, collector ) ); } public static <T, D, K> GroupingBuilder<T, List<T>, K> groupOn(Function<? super T, ? extends K> classifier) { return new GroupingBuilder<>( groupingBy( classifier ) ); } } }