Java8InAction_Chapter06
1 import static java.util.Comparator.comparingInt; 2 import static java.util.stream.Collector.Characteristics.CONCURRENT; 3 import static java.util.stream.Collector.Characteristics.IDENTITY_FINISH; 4 import static java.util.stream.Collectors.collectingAndThen; 5 import static java.util.stream.Collectors.counting; 6 import static java.util.stream.Collectors.groupingBy; 7 import static java.util.stream.Collectors.mapping; 8 import static java.util.stream.Collectors.maxBy; 9 import static java.util.stream.Collectors.partitioningBy; 10 import static java.util.stream.Collectors.reducing; 11 import static java.util.stream.Collectors.summingInt; 12 import static java.util.stream.Collectors.toSet; 13 import static lambdasinaction.chap6.Dish.menu; 14 15 import java.util.ArrayList; 16 import java.util.Collections; 17 import java.util.EnumSet; 18 import java.util.HashMap; 19 import java.util.List; 20 import java.util.Map; 21 import java.util.Optional; 22 import java.util.Set; 23 import java.util.function.BiConsumer; 24 import java.util.function.BinaryOperator; 25 import java.util.function.Function; 26 import java.util.function.Predicate; 27 import java.util.function.Supplier; 28 import java.util.stream.Collector; 29 import java.util.stream.IntStream; 30 import java.util.stream.Stream; 31 32 /** 33 * 在这里编写类的功能描述 34 * 35 * @author shangjinyu 36 * @created 2017/10/5 37 */ 38 public class Notes { 39 40 /** 41 * Collectors类的静态工厂方法 42 * 工厂方法 返回类型 用于 43 * toList List<T> 把流中所有项目收集到一个List 44 * 使用示例: List<Dish> dishes = menuStream.collect(toList()); 45 * toSet Set<T> 把流中所有项目收集到一个Set,删除重复项 46 * 使用示例: Set<Dish> dishes = menuStream.collect(toSet()); 47 * toCollection Collection<T> 把流中所有项目收集到给定的供应源创建的集合 48 * 使用示例: Collection<Dish> dishes = menuStream.collect(toCollection(), ArrayList::new); 49 * counting Long 计算流中元素的个数 50 * 使用示例: long howManyDishes = menuStream.collect(counting()); 51 * summingInt Integer 对流中项目的一个整数属性求和 52 * 使用示例: int totalCalories = menuStream.collect(summingInt(Dish::getCalories)); 53 * averagingInt Double 计算流中项目Integer属性的平均值 54 * 使用示例: double avgCalories = menuStream.collect(averagingInt(Dish::getCalories)); 55 * summarizingInt IntSummaryStatistics 收集关于流中项目Integer属性的统计值,例如最大,最小,总和与平均值 56 * 使用示例: IntSummaryStatistics menuStatistics = menuStream.collect(summarizingInt(Dish::getCalories)); 57 * joing String 连接对流中每个项目调用toString方法所生成的字符串 58 * 使用示例: String shortMenu = menuStream.map(Dish::getName).collect(joining(", ")); 59 * maxBy Optional<T> 一个包裹了流中按照给定比较器选出的最大元素的Optional,或如果流为空则为Optional.empty() 60 * 使用示例: Optional<Dish> fattest = menuStream.collect(maxBy(comparingInt(Dish::getCalories))); 61 * minBy Optional<T> 一个包裹了流中按照给定比较器选出的最小元素的Optional,或如果流为空则为Optional.empty() 62 * 使用示例: Optional<Dish> fattest = menuStream.collect(minBy(comparingInt(Dish::getCalories))); 63 * reducing 规约操作产生的类型 从一个作为累加器的初始值开始,利用BinaryOperator与流中的元素逐个结合,从而将流规约为单个值 64 * 使用示例: int totalCalories = menuStream.collect(reducing(0, Dish::getCalories, Integer::sum)); 65 * collectionAndThen 转换函数返回的类型 包裹另一个收集器,对其结果应用转换函数 66 * 使用示例: int howManyDishes = menuStream.collect(collectingAndThen(toList(), List::size)); 67 * groupingBy Map<K,List<T> 根据项目的一个属性的值对流中的项目分组,并将属性值作为结果Map的键 68 * 使用示例: Map<Dish.Type,List<Dish>> dishesByType = menuStream.collect(groupingBy(Dish::getType)); 69 * partitioningBy Map<Boolean,List<T> 根据对流中每个项目应用谓词的结果来对项目进行分区 70 * 使用 :Map<Boolean,List<Dish>> vegetarianDishes = menuStream.collect(partitioningBy(Dish::isVegetarian)); 71 */ 72 //返回Colletcors接口 73 //counting(), maxBy(), summingInt(), averagingInt(), summarizingInt(), joining(), groupingBy 74 75 //reducing() 76 int totalCalories = menu.stream().collect(reducing( 77 0, Dish::getCalories, (i, j) -> i + j)); 78 79 Optional<Dish> mostCalorieDish = 80 menu.stream().collect(reducing( 81 (d1, d2) -> d1.getCalories() > d2.getCalories() ? d1 : d2)); 82 83 public enum CaloricLevel {DIET, NORMAL, FAT}; 84 85 Map<CaloricLevel, List<Dish>> dishesByCaloricLevel = menu.stream().collect(groupingBy(dish -> { 86 if (dish.getCalories() <= 400) return CaloricLevel.DIET; 87 else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL; 88 else return CaloricLevel.FAT; 89 })); 90 91 //groupingBy() 92 Map<Dish.Type, Map<CaloricLevel, List<Dish>>> dishesByTypeCaloricLevel = menu.stream().collect( 93 groupingBy(Dish::getType, 94 groupingBy(dish -> { 95 if (dish.getCalories() <= 400) return CaloricLevel.DIET; 96 else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL; 97 else return CaloricLevel.FAT; 98 }) 99 ) 100 ); 101 /** 102 * {MEAT={DIET=[chicken], NORMAL=[beef], FAT=[pork]}, 103 * FISH={DIET=[prawns], NORMAL=[salmon]}, 104 * OTHER={DIET=[rice, seasonal fruit], NORMAL=[french fries, pizza]}} 105 */ 106 107 Map<Dish.Type, Long> typesCount = menu.stream().collect( 108 groupingBy(Dish::getType, counting())); 109 //{MEAT=3, FISH=2, OTHER=4} 110 //单参数groupingBy(f) 其中f是分类函数,实际是groupingBy(f, toList())的简写法 111 112 Map<Dish.Type, Optional<Dish>> mostCaloricByType1 = 113 menu.stream() 114 .collect(groupingBy(Dish::getType, 115 maxBy(comparingInt(Dish::getCalories)))); 116 //{FISH=Optional[salmon], OTHER=Optional[pizza], MEAT=Optional[pork]} 117 118 Map<Dish.Type, Dish> mostCaloricByType2 = 119 menu.stream().collect(groupingBy(Dish::getType, 120 collectingAndThen(maxBy(comparingInt(Dish::getCalories)), Optional::get))); 121 //{FISH=salmon, OTHER=pizza, MEAT=pork} 122 123 Map<Dish.Type, Integer> totalCaloriesByType = 124 menu.stream().collect(groupingBy(Dish::getType, 125 summingInt(Dish::getCalories))); 126 127 Map<Dish.Type, Set<CaloricLevel>> caloricLevelsByType = 128 menu.stream().collect( 129 groupingBy(Dish::getType, mapping( 130 dish -> { 131 if (dish.getCalories() <= 400) return CaloricLevel.DIET; 132 else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL; 133 else return CaloricLevel.FAT; 134 }, 135 toSet()))); // toCollection(HashSet::new) ))); 136 //{OTHER=[DIET, NORMAL], MEAT=[DIET, NORMAL, FAT], FISH=[DIET, NORMAL]} 137 138 //partitioningBy() 139 Map<Boolean, List<Dish>> partitionedMenu = menu.stream().collect(partitioningBy(Dish::isVegetarian)); 140 /** 141 * {false=[pork, beef, chicken, prawns, salmon], 142 * true=[french fries, rice, season fruit, pizza]} 143 * <p> 144 * = List<Dish> vegetarianDishes = menu.stream().filter(Dish::isVegetarian).collect(toList()); 145 */ 146 147 Map<Boolean, Map<Dish.Type, List<Dish>>> vegetarianDishesByType = menu.stream().collect( 148 partitioningBy(Dish::isVegetarian, groupingBy(Dish::getType))); 149 /** 150 * {false={FISH=[prawns, salmon], MEAT=[pork, beef, chicken]}, 151 * true={OTHER=[french fries, rice, season fruit, pizza]}} 152 */ 153 154 Map<Boolean, Dish> mostCaloricPartitionedByVegetarian = 155 menu.stream().collect(partitioningBy(Dish::isVegetarian, 156 collectingAndThen(maxBy(comparingInt(Dish::getCalories)), Optional::get))); 157 //{false=pork, true=pizza} 158 159 //假设你要写个方法,它接受参数int n,并将前n个自数分为质数和非质数 160 public boolean isPrime(int candidate) { 161 int candidateRoot = (int) Math.sqrt((double) candidate); 162 return IntStream.rangeClosed(2, candidateRoot) 163 .noneMatch(i -> candidate % i == 0); 164 } 165 166 public Map<Boolean, List<Integer>> partitionPrimes(int n) { 167 return IntStream.rangeClosed(2, n).boxed() 168 .collect( 169 partitioningBy(candidate -> isPrime(candidate))); 170 } 171 //自定义收集器 172 public class ToListCollector<T> implements Collector<T, List<T>, List<T>> { 173 @Override 174 public Supplier<List<T>> supplier(){ 175 return ArrayList::new; 176 } 177 178 @Override 179 public BiConsumer<List<T>, T> accumulator() { 180 return List::add; 181 } 182 183 @Override 184 public BinaryOperator<List<T>> combiner() { 185 return (list1, list2) -> { 186 list1.addAll(list2); 187 return list1; 188 }; 189 } 190 191 @Override 192 public Function<List<T>, List<T>> finisher() { 193 return Function.identity(); 194 } 195 196 @Override 197 public Set<Characteristics> characteristics() { 198 return Collections.unmodifiableSet(EnumSet.of(IDENTITY_FINISH, CONCURRENT)); 199 } 200 201 } 202 203 List<Dish> dishes = menu.stream().collect(ArrayList::new, List::add, List::addAll); 204 205 }
1 public static class PrimeNumbersCollector 2 implements Collector<Integer, Map<Boolean, List<Integer>>, Map<Boolean, List<Integer>>> { 3 4 @Override 5 public Supplier<Map<Boolean, List<Integer>>> supplier() { 6 return () -> new HashMap<Boolean, List<Integer>>() {{ 7 put(true, new ArrayList<Integer>()); 8 put(false, new ArrayList<Integer>()); 9 }}; 10 } 11 12 @Override 13 public BiConsumer<Map<Boolean, List<Integer>>, Integer> accumulator() { 14 return (Map<Boolean, List<Integer>> acc, Integer candidate) -> { 15 acc.get( isPrime( acc.get(true), 16 candidate) ) 17 .add(candidate); 18 }; 19 } 20 21 @Override 22 public BinaryOperator<Map<Boolean, List<Integer>>> combiner() { 23 return (Map<Boolean, List<Integer>> map1, Map<Boolean, List<Integer>> map2) -> { 24 map1.get(true).addAll(map2.get(true)); 25 map1.get(false).addAll(map2.get(false)); 26 return map1; 27 }; 28 } 29 30 @Override 31 public Function<Map<Boolean, List<Integer>>, Map<Boolean, List<Integer>>> finisher() { 32 return i -> i; 33 } 34 35 @Override 36 public Set<Characteristics> characteristics() { 37 return Collections.unmodifiableSet(EnumSet.of(IDENTITY_FINISH)); 38 } 39 } 40 41 public Map<Boolean, List<Integer>> partitionPrimesWithInlineCollector(int n) { 42 return Stream.iterate(2, i -> i + 1).limit(n) 43 .collect( 44 () -> new HashMap<Boolean, List<Integer>>() {{ 45 put(true, new ArrayList<Integer>()); 46 put(false, new ArrayList<Integer>()); 47 }}, 48 (acc, candidate) -> { 49 acc.get( isPrime(acc.get(true), candidate) ) 50 .add(candidate); 51 }, 52 (map1, map2) -> { 53 map1.get(true).addAll(map2.get(true)); 54 map1.get(false).addAll(map2.get(false)); 55 }); 56 } 57 public static boolean isPrime(List<Integer> primes, Integer candidate) { 58 double candidateRoot = Math.sqrt((double) candidate); 59 //return primes.stream().filter(p -> p < candidateRoot).noneMatch(p -> candidate % p == 0); 60 return takeWhile(primes, i -> i <= candidateRoot).stream().noneMatch(i -> candidate % i == 0); 61 } 62 63 public static <A> List<A> takeWhile(List<A> list, Predicate<A> p) { 64 int i = 0; 65 for (A item : list) { 66 if (!p.test(item)) { 67 return list.subList(0, i); 68 } 69 i++; 70 } 71 return list; 72 }