测试 Collectors 类中相关 API,以及 Collector 接口中 Characteristics 的枚举值
1 public static void main(String [] args) { 2 //Stream API 3 List<String> arrList1 = Arrays.asList("predicate1", "collect1", "map1", "flatmap1", "reduce1", "collect1"); 4 List<String> arrList2 = Arrays.asList("predicate2", "collect2", "map2", "flatmap2", "reduce2", "collect2"); 5 List<List<String>> arrAll = Arrays.asList(arrList1, arrList2); 6 System.out.println(arrList1.stream().filter(i -> i.length() > 5).collect(Collectors.toList())); 7 System.out.println(arrList1.stream().map(i -> i.toUpperCase()).collect(Collectors.toList())); 8 //flatmap 将流中数据扁平化处理,其中参数二是一个 Stream 对象。本例中将所有字符数组扁平化到一个流中 9 arrList1.stream().map(i -> i).flatMap(i -> Stream.of(i.toCharArray())).forEach(i -> System.out.println(Arrays.toString(i))); 10 //flatmap 将流中数据扁平化处理,其中参数二是一个 Stream 对象。本例针对的是 List<List<String>> 结构数据,将多个 List 中的数据扁平化到一个流中 11 System.out.println(arrAll.stream().flatMap(i -> i.stream()).collect(Collectors.toList())); 12 //流元素去重 13 System.out.println(arrList1.stream().distinct().collect(Collectors.toList())); 14 //流元素排序 15 System.out.println(arrList1.stream().sorted(String::compareTo).collect(Collectors.toList())); 16 //peek 不影响最终 collect 操作。类似数据预览效果 17 System.out.println(arrList1.stream().peek(i -> { 18 i += "suffix"; 19 System.out.println(i); 20 }).collect(Collectors.toList())); 21 //类似数据库分页查询操作 22 System.out.println(arrList1.stream().skip(1).limit(3).collect(Collectors.toList())); 23 //遍历消费流中元素 24 arrList1.stream().forEach(System.out::println); 25 //流转数组 26 Object[] objects = arrList1.stream().toArray(); 27 //通过 i,可以显示的创建一个大小固定的数组 28 Object[] strings = arrList1.stream().toArray(i -> { 29 System.out.println("i = " + i); 30 return new Object[i]; 31 }); 32 System.out.println(Arrays.toString(strings)); 33 //精简写法,并且可以免去泛型强转的问题 34 String[] strings1 = arrList1.stream().toArray(String[]::new); 35 System.out.println(Arrays.toString(strings1)); 36 //reduce,汇聚操作,对流中的每个元素按一定规则计算,最终输出一个值,内置的汇聚操作有求和、求平均值、最大值等 37 arrList1.stream().reduce((a, b) -> a.concat(b)).ifPresent(i -> System.out.println(i)); 38 System.out.println(arrList1.stream().reduce("prefix", (a, b) -> a.concat(b))); 39 //reduce 的重载形式,计算流中字符的总个数,参数一是一个初始值 40 System.out.println(arrList1.stream().reduce(0, (a, b) -> a += b.length(), (a, b) -> a+= b)); 41 //求最大值和最小值,本质上使用的就是 reduce 42 arrList1.stream().min((a, b) -> a.length() - b.length()).ifPresent(i -> System.out.println(i)); 43 arrList1.stream().max((a, b) -> a.length() - b.length()).ifPresent(i -> System.out.println(i)); 44 //求个数(可以使用 peek 配合 reduce,可以同时得出多个汇聚后的值,而不是一个) 45 System.out.println(arrList1.stream().count()); 46 //任意匹配返回 true 47 System.out.println(arrList1.stream().anyMatch(i -> "map1".equals(i))); 48 //全部匹配返回 true 49 System.out.println(arrList1.stream().allMatch(i -> i.length() > 0)); 50 //全部都不匹配返回 true 51 System.out.println(arrList1.stream().noneMatch(i -> i.length() < 0)); 52 //找出流中第一个元素 53 arrList1.stream().findFirst().ifPresent(i -> System.out.println(i)); 54 //找出流中任意一个元素 55 arrList1.stream().findAny().ifPresent(i -> System.out.println(i)); 56 } 57 58 59 public static void main1(String[] args) { 60 61 62 //Collectors API 63 StringBuilder builder = Stream.of("supplier", "consumer", "producer") 64 .collect(StringBuilder::new, StringBuilder::append, StringBuilder::append); 65 System.out.println(builder); 66 int[] intArr = Arrays.asList(1, 2, 3, 4, 5).stream() 67 .collect(() -> new int[1], (a, b) -> a[0] += b, (a, b) -> a[0] += b[0]); 68 System.out.println(Arrays.toString(intArr)); 69 Collectors collectors; 70 Stream.<String>of().collect(Collectors.<String>toList()); 71 StringJoiner joiner = new StringJoiner(";", "pre", "suf"); 72 joiner.add("supplier").add("consumer").add("producer"); 73 System.out.println("merge : " + joiner.toString()); 74 List<String> list = Arrays.asList("supplier", "consumer", "producer"); 75 //在应用一个下游收集器之前,对流中的元素做一次 map 转换 76 System.out.println(list.stream().collect(Collectors.mapping(String::toUpperCase, Collectors.toList()))); 77 //先应用了一个下游收集器,然后对下游收集器的结果应用一个 Function 进行转换。理解 Charactristic 的几个枚举值 78 String collect = list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), r -> StringUtils.join(r, ";"))); 79 System.out.println(collect); 80 List<Integer> nums = Arrays.asList(1, 3, 5, 7, 9, 11); 81 System.out.println("couting1 : " + nums.stream().collect(Collectors.counting())); 82 Integer collect1 = nums.stream().parallel().collect(new Collector<Integer, int[], Integer>() { 83 @Override 84 public Supplier supplier() { return () -> new int[1]; } 85 86 @Override 87 public BiConsumer<int [], Integer> accumulator() { return (a, b) -> a[0] = 1; } 88 89 @Override 90 public BinaryOperator<int []> combiner() { 91 return (a, b) -> { 92 System.out.println("a = " + a + " , b = " + b); 93 System.out.println(Thread.currentThread().getName() + ":" + a[0] + ":" + b[0]); 94 a[0] = a[0] + b[0]; 95 return a; 96 }; 97 } 98 @Override 99 public Function<int [], Integer> finisher() { return (a) -> a[0];} 100 101 @Override 102 public Set<Characteristics> characteristics() { return Collections.emptySet();} 103 }); 104 System.out.println("couting2 : " + collect1); 105 //其实本质上也是 reduce 的调用,也符合下面的规则,流中元素 -> 输出为一个值 106 nums.stream().collect(Collectors.minBy((a, b) -> a - b)).ifPresent(System.out::println); 107 nums.stream().collect(Collectors.maxBy((a, b) -> a - b)).ifPresent(System.out::println); 108 System.out.println(nums.stream().collect(Collectors.summingInt(a -> a * 2))); 109 //reduce 函数的作用是将流中的多个元素,按照某种规则,输出为一个值。比如统计 Count、求和、元素转 String 等 110 System.out.println(nums.stream().collect(Collectors.<Integer, String>reducing("", a -> "{" + a + "}", (a, b) -> a + b))); 111 Map<String, Object> m1 = new HashMap<>(); 112 m1.put("a", 123); 113 m1.put("b", 456); 114 m1.put("c", 789); 115 //HashMap 中的这个方法,将新值和旧值合并;旧值就是通过 get("a") 获取,新值就是 111。合并规则由 BinaryOperator 指定 116 m1.merge("d", 111, (a, b) -> a + "-" + b); 117 System.out.println(m1); 118 m1.replaceAll((k, v) -> k + '-' + v); 119 System.out.println("after replace All : " + m1); 120 for(Map.Entry<String, Object> entry : m1.entrySet()) { 121 m1.merge(entry.getKey(), "111", (a, b) -> a + "-" + b); 122 } 123 System.out.println(m1); 124 List<String> list1 = Arrays.asList("aaSupplier11", "ccComsumer12", "ccProducer13", "ccEntry14", "aaMap15", "ccProducer16"); 125 Map<String, List<String>> result1 = list1.stream().collect(Collectors.groupingBy(a -> a.startsWith("aa") ? "aa" : "bb")); 126 System.out.println(result1); 127 Map<String, List<String>> result2 = list1.stream().collect( 128 Collectors.<String, String, List<String>, List<String>>groupingBy( 129 a -> a.startsWith("aa") ? "aa" : "cc", (Collector<? super String, List<String>, List<String>>) Collectors.<String>toList())); 130 System.out.println(result2); 131 //最底层的 groupBy,需要提供的有:键的分类器、保存结果的 Map 容器、容器中值对应的类型(一般是 List) 132 Map<String, Set<String>> result3 = list1.stream().collect(Collectors.<String, String, Set<String>, Set<String>, Map<String, Set<String>>>groupingBy( 133 a -> a.startsWith("aa") ? "aa" : "ee", 134 () -> new HashMap<String, Set<String>>() 135 , (Collector<? super String, Set<String>, Set<String>>) Collectors.<String>toSet())); 136 System.out.println(result3); 137 138 //分区,里面有一个对象 Partition,Partition 本质上是一个 Map,并且它的 Key 是 Boolean 类型,该 Map 中仅有两个元素。值是泛型 T,可以是任意类型 139 Map<Boolean, List<String>> result = list1.stream().collect(Collectors.partitioningBy(i -> i.startsWith("cc"), Collectors.toList())); 140 System.out.println(result); 141 142 //toMap,将流中每个元素按照指定规则,转为 map,但要确保流中的元素不会有重复,否则异常 143 Map<String, Integer> result4 = list1.stream().collect(Collectors.toMap(i -> i.toUpperCase(), i -> i.length())); 144 System.out.println(result4); 145 146 List<Integer> intList = Arrays.asList(1, 3, 5, 7, 9); 147 //这个例子也演示了如何通过自定义类的方式来制作一个容器 148 IntSummaryStatistics collect2 = intList.parallelStream().collect(Collectors.summarizingInt(i -> i)); 149 System.out.println(collect2); 150 151 List<String> list0 = new ArrayList<>(); 152 List<String> list2 = Arrays.asList("aaSupplier21", "ccComsumer22", "ccProducer23", "ccEntry24", "aaMap25", "ccProducer26"); 153 List<String> list3 = Arrays.asList("aaSupplier31", "ccComsumer32", "ccProducer33", "ccEntry34", "aaMap35", "ccProducer36"); 154 list0.addAll(list1); 155 list0.addAll(list2); 156 list0.addAll(list3); 157 System.out.println("-------------"); 158 Thread.currentThread().setName("ForkJoinPool.commonPool-worker-M"); 159 //三个枚举值的使用 160 for(int i = 0; i < 1; i++) { 161 List<String> collect3 = list0.parallelStream().collect(new Collector<String, List<String>, List<String>>() { 162 @Override 163 public Supplier<List<String>> supplier() { 164 return () -> { 165 System.out.println("do supplier " + Thread.currentThread().getName()); 166 return new ArrayList<>(); 167 }; 168 } 169 170 @Override 171 public BiConsumer<List<String>, String> accumulator() { 172 return (a, b) -> { 173 a.add(b); 174 //在获取并行流的情况下,如果多线程处理的是一个结果容器,这里不能遍历读取容器中的内容,否则很有可能抛出异常 ConcurrentModificationException 175 //在获取并行流的情况下,除上述情况外,不会有异常出现 176 //System.out.println("do accumulator " + Thread.currentThread().getName() + " " + a); 177 }; 178 } 179 180 @Override 181 public BinaryOperator<List<String>> combiner() { 182 return (a, b) -> { 183 a.addAll(b); 184 System.out.println("do combiner " + Thread.currentThread().getName() + " " + a); 185 return a; 186 }; 187 } 188 189 @Override 190 public Function<List<String>, List<String>> finisher() { 191 return a -> { 192 System.out.println("do finisher " + Thread.currentThread().getName()); 193 return a; 194 }; 195 } 196 197 @Override 198 public Set<Characteristics> characteristics() { 199 System.out.println("do characteristics " + Thread.currentThread().getName()); 200 //在获取了并行流的前提下,当且仅当同时设置了 UNORDERED 和 CONCURRENT 时,combiner 才不会执行,这是因为多线程中,多线程操作的是同一个结果容器 201 //在获取了并行流的情况下,除上述情况外,其他情况都会执行 combiner,这是因为多线程中,每个线程处理一个结果容器,最后会将多个结果容器汇总起来 202 return Collections.unmodifiableSet(EnumSet.of(Characteristics.CONCURRENT, Characteristics.UNORDERED)); 203 //return Collections.emptySet(); 204 } 205 }); 206 System.out.println(collect3); 207 } 208 }