JDK1.8新特性——Collector接口和Collectors工具类
jdk1.8新特性——collector接口和collectors工具类
摘要:本文主要学习了在java1.8中新增的collector接口和collectors工具类,以及使用它们在处理集合时的改进和优化。
部分内容来自以下博客:
https://www.jianshu.com/p/7eaa0969b424
流式处理
jdk1.8中新增的流式处理提供了一种高效且易于使用的处理数据的方式,它可以对集合执行非常复杂的查找、过滤和映射数据等操作,极大的简化了对于集合的使用。借助流式处理,可以像使用sql语句一样对集合进行操作。
jdk1.8通过内部迭代来实现对流的处理,一个流式处理可以分为三个部分:转换成流、中间操作、终止操作。
转换成流
对于集合,可以使用集合类中的stream()方法或者parallelstream()方法将集合转换成流。
中间操作
中间操作可以对流进行处理并返回处理后的流对象,多个中间操作可以连接起来形成一个流水线,直到执行终止操作结束流的执行。
终止操作
终止操作会对经过中间操作后得到的流进行处理,返回任何不是流的数据。
collector接口
在对流进行的终止操作中,有一个方法是collect,其作用是收集元素并进行处理,最终返回处理后的非流对象。
查看其方法定义如下:
1 <r, a> r collect(collector<? super t, a, r> collector);
可以看到,collect方法要求传入一个collector接口的实例对象,collector可以看做是用来处理流的工具,在collectors里面封装了很多collector工具。
全局变量
collector主要包含五个参数,它的行为也是由这五个参数来定义的,如下所示:
1 // supplier参数用于生成结果容器,容器类型为a。 2 supplier<a> supplier(); 3 // accumulator用于归纳元素,泛型t就是元素,它会将流中的元素同结果容器a发生操作。 4 biconsumer<a, t> accumulator(); 5 // combiner用于合并两个并行执行的结果,将其合并为最终结果a。 6 binaryoperator<a> combiner(); 7 // finisher用于将之前完整的结果r转为a。 8 function<a, r> finisher(); 9 // characteristics表示当前collector的特征值,是一个不可变的set。 10 set<characteristics> characteristics();
枚举
characteristics这个特征值是一个枚举:
1 enum characteristics { 2 // 多线程并行。 3 concurrent, 4 // 无序。 5 unordered, 6 // 无需转换结果。 7 identity_finish 8 }
构造方法
collector拥有两个of方法用于生成collector实例,其中一个拥有上面所有五个参数,另一个四个参数,不包括finisher参数。
1 // 四参方法,用于生成一个collector,t代表流中的元素,r代表最终的结果。因为没有finisher参数,所以需要有identity_finish特征值。 2 public static<t, r> collector<t, r, r> of(supplier<r> supplier, 3 biconsumer<r, t> accumulator, 4 binaryoperator<r> combiner, 5 characteristics... characteristics) { 6 objects.requirenonnull(supplier); 7 objects.requirenonnull(accumulator); 8 objects.requirenonnull(combiner); 9 objects.requirenonnull(characteristics); 10 set<characteristics> cs = (characteristics.length == 0) 11 ? collectors.ch_id 12 : collections.unmodifiableset(enumset.of(collector.characteristics.identity_finish, 13 characteristics)); 14 return new collectors.collectorimpl<>(supplier, accumulator, combiner, cs); 15 } 16 17 // 五参方法,用于生成一个collector,t代表流中的元素,a代表中间结果,r代表最终结果,finisher用于将a转换为r。 18 public static<t, a, r> collector<t, a, r> of(supplier<a> supplier, 19 biconsumer<a, t> accumulator, 20 binaryoperator<a> combiner, 21 function<a, r> finisher, 22 characteristics... characteristics) { 23 objects.requirenonnull(supplier); 24 objects.requirenonnull(accumulator); 25 objects.requirenonnull(combiner); 26 objects.requirenonnull(finisher); 27 objects.requirenonnull(characteristics); 28 set<characteristics> cs = collectors.ch_noid; 29 if (characteristics.length > 0) { 30 cs = enumset.noneof(characteristics.class); 31 collections.addall(cs, characteristics); 32 cs = collections.unmodifiableset(cs); 33 } 34 return new collectors.collectorimpl<>(supplier, accumulator, combiner, finisher, cs); 35 }
collectors工具类
collectors是一个工具类,是jdk预实现collector的工具类,它内部提供了多种collector。
tocollection方法
将流中的元素全部放置到一个集合中返回,这里使用collection,泛指多种集合。
方法:
1 public static <t, c extends collection<t>> collector<t, ?, c> tocollection(supplier<c> collectionfactory) { 2 return new collectorimpl<>( 3 collectionfactory, collection<t>::add, 4 (r1, r2) -> { r1.addall(r2); return r1; }, 5 ch_id); 6 }
实例:
1 public static void main(string[] args) { 2 list<string> list = arrays.aslist("123", "521", "100", "228", "838", "250", "345"); 3 system.out.println(list);// [123, 521, 100, 228, 838, 250, 345] 4 linkedlist<string> newlist = list.stream().collect(collectors.tocollection(linkedlist::new)); 5 system.out.println(newlist);// [123, 521, 100, 228, 838, 250, 345] 6 }
tolist方法
将流中的元素放置到一个list集合中返回,默认为arraylist。
方法:
1 public static <t> 2 collector<t, ?, list<t>> tolist() { 3 return new collectorimpl<>( 4 (supplier<list<t>>) arraylist::new, list::add, 5 (left, right) -> { left.addall(right); return left; }, 6 ch_id); 7 }
实例:
1 public static void main(string[] args) { 2 list<string> list = arrays.aslist("123", "521", "100", "228", "838", "250", "345"); 3 system.out.println(list);// [123, 521, 100, 228, 838, 250, 345] 4 list<string> newlist = list.stream().collect(collectors.tolist()); 5 system.out.println(newlist);// [123, 521, 100, 228, 838, 250, 345] 6 }
toset方法
将流中的元素放置到一个set集合中返回,默认为hashset。
方法:
1 public static <t> collector<t, ?, set<t>> toset() { 2 return new collectorimpl<>( 3 (supplier<set<t>>) hashset::new, set::add, 4 (left, right) -> { left.addall(right); return left; }, 5 ch_unordered_id); 6 }
实例:
1 public static void main(string[] args) { 2 list<string> list = arrays.aslist("123", "521", "100", "228", "838", "250", "345"); 3 system.out.println(list);// [123, 521, 100, 228, 838, 250, 345] 4 set<string> newset = list.stream().collect(collectors.toset()); 5 system.out.println(newset);// [100, 123, 521, 345, 228, 838, 250] 6 }
tomap方法
根据传入的键生成器和值生成器,将生成的键和值保存到一个map中返回,键和值的生成都依赖于元素,可以指定出现重复键时的处理方案和保存结果的map。
还有支持并发toconcurrentmap方法,同样有三种重载方法,与tomap基本一致,只是它最后使用的map是并发concurrenthashmap。
方法:
1 // 指定键和值的生成方式,遇到键冲突的情况默认抛出异常,默认使用hashmap。 2 public static <t, k, u> collector<t, ?, map<k,u>> tomap( 3 function<? super t, ? extends k> keymapper, 4 function<? super t, ? extends u> valuemapper) { 5 return tomap(keymapper, valuemapper, throwingmerger(), hashmap::new); 6 } 7 // 指定键和值的生成方式,遇到键冲突的情况使用传入的方法处理,默认使用hashmap。 8 public static <t, k, u> collector<t, ?, map<k,u>> tomap( 9 function<? super t, ? extends k> keymapper, 10 function<? super t, ? extends u> valuemapper, 11 binaryoperator<u> mergefunction) { 12 return tomap(keymapper, valuemapper, mergefunction, hashmap::new); 13 } 14 // 指定键和值的生成方式,遇到键冲突的情况使用传入的方法处理,使用传入的map类型返回数据。前两种方式最终还是调用此方法来返回map数据。 15 public static <t, k, u, m extends map<k, u>> collector<t, ?, m> tomap( 16 function<? super t, ? extends k> keymapper, 17 function<? super t, ? extends u> valuemapper, 18 binaryoperator<u> mergefunction, 19 supplier<m> mapsupplier) { 20 biconsumer<m, t> accumulator = (map, element) -> map.merge( 21 keymapper.apply(element), 22 valuemapper.apply(element), 23 mergefunction); 24 return new collectorimpl<>(mapsupplier, accumulator, mapmerger(mergefunction), ch_id); 25 }
实例:
1 public static void main(string[] args) { 2 map<string, string> newmap = null; 3 list<string> list = arrays.aslist("123", "521", "100", "228", "838", "250", "345"); 4 system.out.println(list);// [123, 521, 100, 228, 838, 250, 345] 5 // 123和100的键都是1,导致冲突,默认抛出异常,使用limit截取前两个元素。 6 newmap = list.stream().limit(2).collect(collectors.tomap(e -> e.substring(0, 1), e -> e)); 7 system.out.println(newmap);// {1=123, 5=521} 8 // 传入主键冲突时的处理方法,保留先插入的值,默认使用hashmap,对主键由小到大排序。 9 newmap = list.stream().collect(collectors.tomap(e -> e.substring(0, 1), e -> e, (m, n) -> m)); 10 system.out.println(newmap);// {1=123, 2=228, 3=345, 5=521, 8=838} 11 // 传入主键冲突时的处理方法,保留新插入的值,默认使用linkedhashmap,对主键按照插入顺序排序。 12 newmap = list.stream().collect(collectors.tomap(e -> e.substring(0, 1), e -> e, (m, n) -> n, linkedhashmap::new)); 13 system.out.println(newmap);// {1=100, 5=521, 2=250, 8=838, 3=345} 14 }
joining方法
将流中的元素全部以字符串的方式连接到一起,可以指定连接符,也可以指定前后缀。
方法:
1 // 将流中的元素全部以字符串的方式连接到一起,不使用连接符,也不指定前后缀。 2 public static collector<charsequence, ?, string> joining() { 3 return new collectorimpl<charsequence, stringbuilder, string>( 4 stringbuilder::new, stringbuilder::append, 5 (r1, r2) -> { r1.append(r2); return r1; }, 6 stringbuilder::tostring, ch_noid); 7 } 8 // 将流中的元素全部以字符串的方式连接到一起,使用指定的连接符,不指定前后缀。 9 public static collector<charsequence, ?, string> joining(charsequence delimiter) { 10 return joining(delimiter, "", ""); 11 } 12 // 将流中的元素全部以字符串的方式连接到一起,使用指定的连接符,使用指定的前后缀。 13 public static collector<charsequence, ?, string> joining(charsequence delimiter, 14 charsequence prefix, 15 charsequence suffix) { 16 return new collectorimpl<>( 17 () -> new stringjoiner(delimiter, prefix, suffix), 18 stringjoiner::add, stringjoiner::merge, 19 stringjoiner::tostring, ch_noid); 20 }
实例:
1 public static void main(string[] args) { 2 string str = null; 3 list<string> list = arrays.aslist("123", "521", "100", "228", "838", "250", "345"); 4 system.out.println(list);// [123, 521, 100, 228, 838, 250, 345] 5 str = list.stream().collect(collectors.joining()); 6 system.out.println(str);// 123521100228838250345 7 str = list.stream().collect(collectors.joining("-")); 8 system.out.println(str);// 123-521-100-228-838-250-345 9 str = list.stream().collect(collectors.joining("-", "<", ">")); 10 system.out.println(str);// <123-521-100-228-838-250-345> 11 }
mapping方法
将流中的元素按照传入的方法进行处理,并将结果按照指定的格式返回。
方法:
1 public static <t, u, a, r> 2 collector<t, ?, r> mapping( 3 function<? super t, ? extends u> mapper, 4 collector<? super u, a, r> downstream) { 5 biconsumer<a, ? super u> downstreamaccumulator = downstream.accumulator(); 6 return new collectorimpl<>( 7 downstream.supplier(), 8 (r, t) -> downstreamaccumulator.accept(r, mapper.apply(t)), 9 downstream.combiner(), 10 downstream.finisher(), 11 downstream.characteristics()); 12 }
实例:
1 public static void main(string[] args) { 2 list<score> scorelist = new arraylist<score>(); 3 scorelist.add(new score("2019", "10", "张三", 1)); 4 scorelist.add(new score("2019", "11", "李四", 1)); 5 scorelist.add(new score("2019", "12", "王五", 1)); 6 list<string> names = scorelist.stream().collect(collectors.mapping(score::getname, collectors.tolist())); 7 system.out.println(names);// [张三, 李四, 王五] 8 }
collectingandthen方法
该方法是按照传入的collector处理完之后,对归纳的结果进行再处理。
方法:
1 public static<t,a,r,rr> collector<t,a,rr> collectingandthen( 2 collector<t,a,r> downstream, 3 function<r,rr> finisher) { 4 set<collector.characteristics> characteristics = downstream.characteristics(); 5 if (characteristics.contains(collector.characteristics.identity_finish)) { 6 if (characteristics.size() == 1) 7 characteristics = collectors.ch_noid; 8 else { 9 characteristics = enumset.copyof(characteristics); 10 characteristics.remove(collector.characteristics.identity_finish); 11 characteristics = collections.unmodifiableset(characteristics); 12 } 13 } 14 return new collectorimpl<>(downstream.supplier(), 15 downstream.accumulator(), 16 downstream.combiner(), 17 downstream.finisher().andthen(finisher), 18 characteristics); 19 }
实例:
1 public static void main(string[] args) { 2 list<string> list = arrays.aslist("123", "521", "100", "228", "838", "250", "345"); 3 system.out.println(list);// [123, 521, 100, 228, 838, 250, 345] 4 integer size = list.stream().collect(collectors.collectingandthen(collectors.tolist(), list::size)); 5 system.out.println(size);// 7 6 }
counting方法
该方法主要用来计数。
方法:
1 public static <t> collector<t, ?, long> counting() { 2 return reducing(0l, e -> 1l, long::sum); 3 }
实例:
1 public static void main(string[] args) { 2 list<string> list = arrays.aslist("123", "521", "100", "228", "838", "250", "345"); 3 system.out.println(list);// [123, 521, 100, 228, 838, 250, 345] 4 long count = list.stream().collect(collectors.counting()); 5 system.out.println(count);// 7 6 }
reducing方法
对流中的元素做统计归纳,有三个重载方法,和stream里的三个reduce方法对应,二者是可以替换使用的,作用完全一致。
方法:
1 // 返回一个可以直接产生optional类型结果的collector,没有初始值。 2 public static <t> collector<t, ?, optional<t>> reducing(binaryoperator<t> op) { 3 class optionalbox implements consumer<t> { 4 t value = null; 5 boolean present = false; 6 7 @override 8 public void accept(t t) { 9 if (present) { 10 value = op.apply(value, t); 11 } 12 else { 13 value = t; 14 present = true; 15 } 16 } 17 } 18 return new collectorimpl<t, optionalbox, optional<t>>( 19 optionalbox::new, optionalbox::accept, 20 (a, b) -> { if (b.present) a.accept(b.value); return a; }, 21 a -> optional.ofnullable(a.value), ch_noid); 22 } 23 // 返回一个可以直接产生结果的collector,指定初始值。 24 public static <t> collector<t, ?, t> reducing(t identity, binaryoperator<t> op) { 25 return new collectorimpl<>( 26 boxsupplier(identity), 27 (a, t) -> { a[0] = op.apply(a[0], t); }, 28 (a, b) -> { a[0] = op.apply(a[0], b[0]); return a; }, 29 a -> a[0], 30 ch_noid); 31 } 32 // 返回一个可以直接产生结果的collector,指定初始值,在返回结果之前先使用传入的方法将流进行转换。 33 public static <t, u> collector<t, ?, u> reducing( 34 u identity, 35 function<? super t, ? extends u> mapper, 36 binaryoperator<u> op) { 37 return new collectorimpl<>( 38 boxsupplier(identity), 39 (a, t) -> { a[0] = op.apply(a[0], mapper.apply(t)); }, 40 (a, b) -> { a[0] = op.apply(a[0], b[0]); return a; }, 41 a -> a[0], ch_noid); 42 }
实例:
1 public static void main(string[] args) { 2 list<string> list = arrays.aslist("123", "521", "100", "228", "838", "250", "345"); 3 system.out.println(list);// [123, 521, 100, 228, 838, 250, 345] 4 optional<integer> optional = list.stream().limit(4).map(string::length).collect(collectors.reducing(integer::sum)); 5 system.out.println(optional);// optional[12] 6 integer integer = list.stream().limit(3).map(string::length).collect(collectors.reducing(0, integer::sum)); 7 system.out.println(integer);// 9 8 integer sum = list.stream().limit(4).collect(collectors.reducing(0, string::length, integer::sum)); 9 system.out.println(sum);// 12 10 }
minby方法和maxby方法
生成一个用于获取最小值或者最大值的optional结果的collector。
方法:
1 public static <t> collector<t, ?, optional<t>> minby(comparator<? super t> comparator) { 2 return reducing(binaryoperator.minby(comparator)); 3 } 4 public static <t> collector<t, ?, optional<t>> maxby(comparator<? super t> comparator) { 5 return reducing(binaryoperator.maxby(comparator)); 6 }
实例:
1 public static void main(string[] args) { 2 list<string> list = arrays.aslist("123", "521", "100", "228", "838", "250", "345"); 3 system.out.println(list);// [123, 521, 100, 228, 838, 250, 345] 4 optional<string> max = list.stream().collect(collectors.maxby((m, n) -> integer.valueof(m) - integer.valueof(n))); 5 system.out.println(max);// optional[838] 6 optional<string> min = list.stream().collect(collectors.minby((m, n) -> integer.valueof(m) - integer.valueof(n))); 7 system.out.println(min);// optional[100] 8 }
summingint方法、summinglong方法和summingdouble方法
生成一个用于求元素和的collector,首先将元素转换类型,然后再求和。
参数的作用就是将元素转换为指定的类型,最后结果与转换后类型一致。
方法:
1 public static <t> collector<t, ?, integer> summingint(tointfunction<? super t> mapper) { 2 return new collectorimpl<>( 3 () -> new int[1], 4 (a, t) -> { a[0] += mapper.applyasint(t); }, 5 (a, b) -> { a[0] += b[0]; return a; }, 6 a -> a[0], ch_noid); 7 } 8 public static <t> collector<t, ?, long> summinglong(tolongfunction<? super t> mapper) { 9 return new collectorimpl<>( 10 () -> new long[1], 11 (a, t) -> { a[0] += mapper.applyaslong(t); }, 12 (a, b) -> { a[0] += b[0]; return a; }, 13 a -> a[0], ch_noid); 14 } 15 public static <t> collector<t, ?, double> summingdouble(todoublefunction<? super t> mapper) { 16 return new collectorimpl<>( 17 () -> new double[3], 18 (a, t) -> { sumwithcompensation(a, mapper.applyasdouble(t)); 19 a[2] += mapper.applyasdouble(t); }, 20 (a, b) -> { sumwithcompensation(a, b[0]); 21 a[2] += b[2]; return sumwithcompensation(a, b[1]); }, 22 a -> computefinalsum(a), ch_noid); 23 }
实例:
1 public static void main(string[] args) { 2 list<string> list = arrays.aslist("123", "521", "100", "228", "838", "250", "345"); 3 system.out.println(list);// [123, 521, 100, 228, 838, 250, 345] 4 integer intcollect = list.stream().collect(collectors.summingint(integer::parseint)); 5 system.out.println(intcollect);// 2405 6 long longcollect = list.stream().collect(collectors.summinglong(long::parselong)); 7 system.out.println(longcollect);// 2405 8 double doublecollect = list.stream().collect(collectors.summingdouble(double::parsedouble)); 9 system.out.println(doublecollect);// 2405.0 10 }
summarizingint方法、summarizinglong方法和summarizingdouble方法
这三个方法适用于汇总的,返回值分别是intsummarystatistics、longsummarystatistics和doublesummarystatistics。
在这些返回值中包含有流中元素的指定结果的数量、和、最大值、最小值、平均值。
方法:
1 public static <t> collector<t, ?, intsummarystatistics> summarizingint(tointfunction<? super t> mapper) { 2 return new collectorimpl<t, intsummarystatistics, intsummarystatistics>( 3 intsummarystatistics::new, 4 (r, t) -> r.accept(mapper.applyasint(t)), 5 (l, r) -> { l.combine(r); return l; }, ch_id); 6 } 7 public static <t> collector<t, ?, longsummarystatistics> summarizinglong(tolongfunction<? super t> mapper) { 8 return new collectorimpl<t, longsummarystatistics, longsummarystatistics>( 9 longsummarystatistics::new, 10 (r, t) -> r.accept(mapper.applyaslong(t)), 11 (l, r) -> { l.combine(r); return l; }, ch_id); 12 } 13 public static <t> collector<t, ?, doublesummarystatistics> summarizingdouble(todoublefunction<? super t> mapper) { 14 return new collectorimpl<t, doublesummarystatistics, doublesummarystatistics>( 15 doublesummarystatistics::new, 16 (r, t) -> r.accept(mapper.applyasdouble(t)), 17 (l, r) -> { l.combine(r); return l; }, ch_id); 18 }
实例:
1 public static void main(string[] args) { 2 list<string> list = arrays.aslist("123", "521", "100", "228", "838", "250", "345"); 3 system.out.println(list);// [123, 521, 100, 228, 838, 250, 345] 4 intsummarystatistics intsummarystatistics = list.stream().collect(collectors.summarizingint(integer::parseint)); 5 system.out.println(intsummarystatistics);// {count=7, sum=2405, min=100, average=343.571429, max=838} 6 longsummarystatistics longsummarystatistics = list.stream().collect(collectors.summarizinglong(long::parselong)); 7 system.out.println(longsummarystatistics);// {count=7, sum=2405, min=100, average=343.571429, max=838} 8 doublesummarystatistics doublesummarystatistics = list.stream().collect(collectors.summarizingdouble(double::parsedouble)); 9 system.out.println(doublesummarystatistics);// {count=7, sum=2405.000000, min=100.000000, average=343.571429, max=838.000000} 10 }
averagingint方法、averaginglong方法和averagingdouble方法
生成一个用于求元素平均值的collector,首先将元素转换类型,然后再求平均值。
参数的作用就是将元素转换为指定的类型,求平均值涉及到除法操作,结果一律为double类型。
方法:
1 public static <t> collector<t, ?, double> averagingint(tointfunction<? super t> mapper) { 2 return new collectorimpl<>( 3 () -> new long[2], 4 (a, t) -> { a[0] += mapper.applyasint(t); a[1]++; }, 5 (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; }, 6 a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1], ch_noid); 7 } 8 public static <t> collector<t, ?, double> averaginglong(tolongfunction<? super t> mapper) { 9 return new collectorimpl<>( 10 () -> new long[2], 11 (a, t) -> { a[0] += mapper.applyaslong(t); a[1]++; }, 12 (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; }, 13 a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1], ch_noid); 14 } 15 public static <t> collector<t, ?, double> averagingdouble(todoublefunction<? super t> mapper) { 16 return new collectorimpl<>( 17 () -> new double[4], 18 (a, t) -> { sumwithcompensation(a, mapper.applyasdouble(t)); a[2]++; a[3]+= mapper.applyasdouble(t); }, 19 (a, b) -> { sumwithcompensation(a, b[0]); sumwithcompensation(a, b[1]); a[2] += b[2]; a[3] += b[3]; return a; }, 20 a -> (a[2] == 0) ? 0.0d : (computefinalsum(a) / a[2]), ch_noid); 21 }
实例:
1 public static void main(string[] args) { 2 list<string> list = arrays.aslist("123", "521", "100", "228", "838", "250", "345"); 3 system.out.println(list);// [123, 521, 100, 228, 838, 250, 345] 4 double intaverage = list.stream().collect(collectors.averagingint(integer::parseint)); 5 system.out.println(intaverage);// 343.57142857142856 6 double longaverage = list.stream().collect(collectors.averaginglong(long::parselong)); 7 system.out.println(longaverage);// 343.57142857142856 8 double doubleaverage = list.stream().collect(collectors.averagingdouble(double::parsedouble)); 9 system.out.println(doubleaverage);// 343.57142857142856 10 }
groupingby方法
生成一个拥有分组功能的collector,有三个重载方法。
方法:
1 // 只需一个分组参数classifier,内部自动将结果保存到一个map中,每个map键的类型即classifier的结果类型,默认将组的元素保存在list中。 2 public static <t, k> collector<t, ?, map<k, list<t>>> groupingby( 3 function<? super t, ? extends k> classifier) { 4 return groupingby(classifier, tolist()); 5 } 6 // 在上面方法的基础上增加了对流中元素的处理方式的collector,默认是list。 7 public static <t, k, a, d> collector<t, ?, map<k, d>> groupingby( 8 function<? super t, ? extends k> classifier, 9 collector<? super t, a, d> downstream) { 10 return groupingby(classifier, hashmap::new, downstream); 11 } 12 // 在第二个方法的基础上再添加了结果map的生成方法,默认是hashmap。 13 public static <t, k, d, a, m extends map<k, d>> collector<t, ?, m> groupingby( 14 function<? super t, ? extends k> classifier, 15 supplier<m> mapfactory, 16 collector<? super t, a, d> downstream) { 17 supplier<a> downstreamsupplier = downstream.supplier(); 18 biconsumer<a, ? super t> downstreamaccumulator = downstream.accumulator(); 19 biconsumer<map<k, a>, t> accumulator = (m, t) -> { 20 k key = objects.requirenonnull(classifier.apply(t), "element cannot be mapped to a null key"); 21 a container = m.computeifabsent(key, k -> downstreamsupplier.get()); 22 downstreamaccumulator.accept(container, t); 23 }; 24 binaryoperator<map<k, a>> merger = collectors.<k, a, map<k, a>>mapmerger(downstream.combiner()); 25 @suppresswarnings("unchecked") 26 supplier<map<k, a>> mangledfactory = (supplier<map<k, a>>) mapfactory; 27 28 if (downstream.characteristics().contains(collector.characteristics.identity_finish)) { 29 return new collectorimpl<>(mangledfactory, accumulator, merger, ch_id); 30 } 31 else { 32 @suppresswarnings("unchecked") 33 function<a, a> downstreamfinisher = (function<a, a>) downstream.finisher(); 34 function<map<k, a>, m> finisher = intermediate -> { 35 intermediate.replaceall((k, v) -> downstreamfinisher.apply(v)); 36 @suppresswarnings("unchecked") 37 m castresult = (m) intermediate; 38 return castresult; 39 }; 40 return new collectorimpl<>(mangledfactory, accumulator, merger, finisher, ch_noid); 41 } 42 }
实例:
1 public static void main(string[] args) { 2 list<string> list = arrays.aslist("123", "521", "100", "228", "838", "250", "345"); 3 system.out.println(list);// [123, 521, 100, 228, 838, 250, 345] 4 map<string, list<string>> groupbyfirst = list.stream().collect(collectors.groupingby(e -> e.substring(0, 1))); 5 system.out.println(groupbyfirst);// {1=[123, 100], 2=[228, 250], 3=[345], 5=[521], 8=[838]} 6 map<string, set<string>> groupbylast = list.stream().collect(collectors.groupingby(e -> e.substring(e.length() - 1), collectors.toset())); 7 system.out.println(groupbylast);// {0=[100, 250], 1=[521], 3=[123], 5=[345], 8=[228, 838]} 8 map<integer, set<string>> groupbylength = list.stream().collect(collectors.groupingby(string::length, hashmap::new, collectors.toset())); 9 system.out.println(groupbylength);// {3=[100, 123, 521, 345, 228, 838, 250]} 10 }
partitioningby方法
将流中的元素按照给定的校验规则的结果分为两个部分,放到map中返回,键是boolean类型,值为元素的列表list。
方法:
1 // 只需一个校验参数predicate。 2 public static <t> collector<t, ?, map<boolean, list<t>>> partitioningby(predicate<? super t> predicate) { 3 return partitioningby(predicate, tolist()); 4 } 5 // 在上面方法的基础上增加了对流中元素的处理方式的collector,默认的处理方法就是collectors.tolist()。 6 public static <t, d, a> collector<t, ?, map<boolean, d>> partitioningby(predicate<? super t> predicate, 7 collector<? super t, a, d> downstream) { 8 biconsumer<a, ? super t> downstreamaccumulator = downstream.accumulator(); 9 biconsumer<partition<a>, t> accumulator = (result, t) -> 10 downstreamaccumulator.accept(predicate.test(t) ? result.fortrue : result.forfalse, t); 11 binaryoperator<a> op = downstream.combiner(); 12 binaryoperator<partition<a>> merger = (left, right) -> 13 new partition<>(op.apply(left.fortrue, right.fortrue), 14 op.apply(left.forfalse, right.forfalse)); 15 supplier<partition<a>> supplier = () -> 16 new partition<>(downstream.supplier().get(), 17 downstream.supplier().get()); 18 if (downstream.characteristics().contains(collector.characteristics.identity_finish)) { 19 return new collectorimpl<>(supplier, accumulator, merger, ch_id); 20 } 21 else { 22 function<partition<a>, map<boolean, d>> finisher = par -> 23 new partition<>(downstream.finisher().apply(par.fortrue), 24 downstream.finisher().apply(par.forfalse)); 25 return new collectorimpl<>(supplier, accumulator, merger, finisher, ch_noid); 26 } 27 }
实例:
1 public static void main(string[] args) { 2 list<string> list = arrays.aslist("123", "521", "100", "228", "838", "250", "345"); 3 system.out.println(list);// [123, 521, 100, 228, 838, 250, 345] 4 map<boolean, list<string>> morethan = list.stream().collect(collectors.partitioningby(e -> integer.parseint(e) > 300)); 5 system.out.println(morethan);// {false=[123, 100, 228, 250], true=[521, 838, 345]} 6 map<boolean, set<string>> lessthan = list.stream().collect(collectors.partitioningby(e -> integer.parseint(e) < 300, collectors.toset())); 7 system.out.println(lessthan);// {false=[521, 345, 838], true=[100, 123, 228, 250]} 8 }