Collectors
中提供了很多好用的 Collector
实现,大大提高了我们的生产力,比如,将元素放入 Collection
,一些聚合、汇总、分组操作。
转集合:toCollection、toList、toSet
toCollection()
可以转成任意的Collection
实现类toList
转成ArrayList
toSet
转成HashSet
public static void main(String[] args) {
String[] arr = {"a", "b", "c", "d"};
toCollection(arr);
}
public static void toCollection(String[] arr) {
ArrayList<String> list1 = Arrays.stream(arr).collect(Collectors.toCollection(ArrayList::new));
System.out.println(list1);
List<String> list2 = Arrays.stream(arr).collect(Collectors.toList());
System.out.println(list2);
Set<String> set = Arrays.stream(arr).collect(Collectors.toSet());
System.out.println(set);
}
[a, b, c, d]
[a, b, c, d]
[a, b, c, d][a, b, c, d]
转Map:toMap、toConcurrentMap
toMap
// 创建 HashMap,有重复 key 时抛异常 java.lang.IllegalStateException: Duplicate key
public static <T, K, U>
Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper);
// 在上面的基础上,当出现 key 重复时,自定义对 value 的处理策略,(阿里手册强制使用)。
public static <T, K, U>
Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper,
BinaryOperator<U> mergeFunction)
// 在上面的基础上,可以自由控制 Map 的类型
public static <T, K, U, M extends Map<K, U>>
Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper,
BinaryOperator<U> mergeFunction,
Supplier<M> mapSupplier)
@Data
private static class Person {
private String name;
private String address;
public Person(String name, String address) {
this.name = name;
this.address = address;
}
public static Person of(String name, String address) {
return new Person(name, address);
}
}
public static void toMap(List<Person> list) {
Map<String, String> map1 = list.stream().collect(Collectors.toMap(
Person::getName, Person::getAddress, (v1, v2) -> v1 + " " + v2, TreeMap::new));
Map<String, String> map2 = list.stream().collect(Collectors.toMap(
Person::getName, Person::getAddress, (v1, v2) -> v1 + " " + v2));
System.out.println(map1.getClass() + " - " + map1);
System.out.println(map2.getClass() + " - " + map2);
Map<String, String> map3 = list.stream().collect(Collectors.toMap(
Person::getName, Person::getAddress));
System.out.println(map3.getClass() + " - " + map3);
}
没有重复 key
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(Person.of("张三", "北京"));
list.add(Person.of("李四", "上海"));
list.add(Person.of("王五", "深圳"));
toMap(list);
}
class java.util.TreeMap - {张三=北京, 李四=上海, 王五=深圳}
class java.util.HashMap - {李四=上海, 张三=北京, 王五=深圳}
class java.util.HashMap - {李四=上海, 张三=北京, 王五=深圳}
存在重复 key
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(Person.of("张三", "北京"));
list.add(Person.of("李四", "上海"));
list.add(Person.of("李四", "深圳"));
toMap(list);
}
class java.util.TreeMap - {张三=北京, 李四=上海 深圳}
class java.util.HashMap - {李四=上海 深圳, 张三=北京}
Exception in thread "main" java.lang.IllegalStateException: Duplicate key 上海
at java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133)
at java.util.HashMap.merge(HashMap.java:1254)
at java.util.stream.Collectors.lambda$toMap$58(Collectors.java:1320)
at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1384)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
at com.example.heima.collectors.ToMap1.toMap(ToMap1.java:39)
at com.example.heima.collectors.ToMap1.main(ToMap1.java:26)
toConcurrentMap
有 toMap
的几个方法相似,但会创建 ConcurrentMap
public static <T, K, U>
Collector<T, ?, ConcurrentMap<K,U>> toConcurrentMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper)
public static <T, K, U>
Collector<T, ?, ConcurrentMap<K,U>> toConcurrentMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper,
BinaryOperator<U> mergeFunction)
public static <T, K, U, M extends ConcurrentMap<K, U>>
Collector<T, ?, M> toConcurrentMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper,
BinaryOperator<U> mergeFunction,
Supplier<M> mapSupplier)
字符串拼接:joining
// 直接拼接,没有分隔符
public static Collector<CharSequence, ?, String> joining()
// 指定分隔符
public static Collector<CharSequence, ?, String> joining(CharSequence delimiter)
// 指定分隔符、前缀、后缀
public static Collector<CharSequence, ?, String> joining(CharSequence delimiter,
CharSequence prefix,
CharSequence suffix)
public static void main(String[] args) {
String[] arr = {"a", "b", "c", "d"};
List<String> list = Arrays.asList(arr);
String s1 = list.stream().collect(Collectors.joining());
String s2 = list.stream().collect(Collectors.joining(","));
String s3 = list.stream().collect(Collectors.joining(",", "[", "]"));
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
}
abcd
a,b,c,d
[a,b,c,d]
适配器:mapping
// 先执行一个 mapper,将T 映射成 U,再执行另一个 Collector
public static <T, U, A, R>
Collector<T, ?, R> mapping(Function<? super T, ? extends U> mapper,
Collector<? super U, A, R> downstream)
public static void main(String[] args) {
String[] arr = {"a", "ab", "abc"};
List<Integer> list = Arrays.stream(arr).collect(
Collectors.mapping(String::length, Collectors.toList()));
System.out.println(list);
}
[1, 2, 3]
先归纳再处理:collectingAndThen
// 先执行 downstream,然后将 downstream 的返回值 R 转为 RR 类型
public static<T,A,R,RR> Collector<T,A,RR> collectingAndThen(Collector<T,A,R> downstream,
Function<R,RR> finisher)
// 先转 Set,再取 size
public static void main(String[] args) {
String[] arr = {"a", "b", "c", "d", "a", "b"};
int size = Arrays.stream(arr).collect(
Collectors.collectingAndThen(Collectors.toSet(), Set::size));
System.out.println(size);
}
4
聚合操作
计数:counting
public static void main(String[] args) {
String[] arr = {"a", "b", "c", "d"};
Long count = Arrays.stream(arr).collect(Collectors.counting());
System.out.println(count);
}
4
最大最小值:maxBy、minBy
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(Person.of("张三", 18));
list.add(Person.of("李四", 25));
list.add(Person.of("王五", 15));
Optional<Person> min = list.stream().collect(
Collectors.minBy(Comparator.comparingInt(Person::getAge)));
Optional<Person> max = list.stream().collect(
Collectors.maxBy(Comparator.comparingInt(Person::getAge)));
System.out.println(min);
System.out.println(max);
}
@Data
@AllArgsConstructor
private static class Person {
private String name;
private int age;
public static Person of(String name, int age) {
return new Person(name, age);
}
}
Optional[MinMax.Person(name=王五, age=15)]
Optional[MinMax.Person(name=李四, age=25)]
求和:summingInt、summingLong、summingDouble
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(Person.of("张三", 18));
list.add(Person.of("李四", 25));
list.add(Person.of("王五", 15));
Integer ageSum = list.stream().collect(Collectors.summingInt(Person::getAge));
Integer lengthSum = list.stream().collect(Collectors.summingInt((p) -> p.getName().length()));
System.out.println(ageSum);
System.out.println(lengthSum);
}
@Data
@AllArgsConstructor
private static class Person {
private String name;
private int age;
public static Person of(String name, int age) {
return new Person(name, age);
}
}
58
6
平均数:averagingInt、averagingLong、averagingDouble
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(Person.of("张三", 18));
list.add(Person.of("李四", 25));
list.add(Person.of("王五", 15));
Double ageAvg = list.stream().collect(Collectors.averagingInt(Person::getAge));
Double lengAvg = list.stream().collect(Collectors.averagingInt((p) -> p.getName().length()));
System.out.println(ageAvg);
System.out.println(lengAvg);
}
@Data
@AllArgsConstructor
private static class Person {
private String name;
private int age;
public static Person of(String name, int age) {
return new Person(name, age);
}
}
19.333333333333332
2.0
reducing
BinaryOperator
是一个二元的函数,BinaryOperator<T> extends BiFunction<T,T,T>
,输入两个参数,返回一个结果,且参数和返回值都是相同类型的 。
reducing()
返回的 Collector
会利用 BinaryOperator
进行元素的 reduce 操作,即 (T, T) -> T
。
// 利用 op 对元素执行 reduce 操作,返回值为 Optional<T>
public static <T> Collector<T, ?, Optional<T>> reducing(BinaryOperator<T> op)
// 在上面的基础上添加了初始值 identity,
public static <T> Collector<T, ?, T> reducing(T identity, BinaryOperator<T> op)
// 在上面的基础上添加了 mapper 函数,可将输入的元素从类型 T 转换成 U,再进行 reduce 操作
public static <T, U> Collector<T, ?, U> reducing(U identity,
Function<? super T, ? extends U> mapper,
BinaryOperator<U> op)
实现 minBy、maxBy 功能
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(Person.of("张三", 18));
list.add(Person.of("李四", 25));
list.add(Person.of("王五", 15));
Optional<Person> min = list.stream().collect(
Collectors.reducing(BinaryOperator.minBy(Comparator.comparingInt(Person::getAge))));
Optional<Person> max = list.stream().collect(
Collectors.reducing(BinaryOperator.maxBy(Comparator.comparingInt(Person::getAge))));
System.out.println(min);
System.out.println(max);
}
@Data
@AllArgsConstructor
private static class Person {
private String name;
private int age;
public static Person of(String name, int age) {
return new Person(name, age);
}
}
Optional[Reducing1.Person(name=王五, age=15)]
Optional[Reducing1.Person(name=李四, age=25)]
实现 counting 功能
public static void main(String[] args) {
String[] arr = {"a", "b", "c", "d"};
Long count = Arrays.stream(arr).collect(Collectors.reducing(0L, e -> 1L, Long::sum));
System.out.println(count);
}
4
按 city 分组,每个城市的最高身高
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(Person.of("北京", 160));
list.add(Person.of("北京", 181));
list.add(Person.of("上海", 179));
list.add(Person.of("上海", 171));
list.add(Person.of("深圳", 190));
list.add(Person.of("深圳", 166));
Map<String, Integer> map = list.stream().collect(Collectors.groupingBy(Person::getCity,
Collectors.reducing(0, Person::getHeight,
BinaryOperator.maxBy(Comparator.comparing(Function.identity())))));
System.out.println(map);
}
@Data
@AllArgsConstructor
private static class Person {
private String city;
private int height;
public static Person of(String city, int height) {
return new Person(city, height);
}
}
{上海=179, 深圳=190, 北京=181}
分组:groupingBy、groupingByConcurrent
groupingBy
// 按照 classifier 的返回值进行分组,默认创建 HashMap,key 为 classifier 的返回值,value 为输入元素的 List
public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy(
Function<? super T, ? extends K> classifier)
// 上面的基础上,Map 的 value 类型由 downstream 指定,比如 Collectors.toSet()
public static <T, K, A, D>
Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier,
Collector<? super T, A, D> downstream)
// 在上面的基础上,有 mapFactory 创建 Map,比如 TreeMap::new
public static <T, K, D, A, M extends Map<K, D>>
Collector<T, ?, M> groupingBy(Function<? super T, ? extends K> classifier,
Supplier<M> mapFactory,
Collector<? super T, A, D> downstream)
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(Person.of("北京", "张三"));
list.add(Person.of("上海", "李四"));
list.add(Person.of("深圳", "王五"));
list.add(Person.of("北京", "小明"));
list.add(Person.of("深圳", "小红"));
groupingBy(list);
}
public static void groupingBy(List<Person> list) {
Map<String, List<Person>> map1 = list.stream().collect(
Collectors.groupingBy(Person::getCity));
Map<String, Set<Person>> map2 = list.stream().collect(
Collectors.groupingBy(Person::getCity, Collectors.toSet()));
TreeMap<String, Set<Person>> map3 = list.stream().collect(
Collectors.groupingBy(Person::getCity, TreeMap::new, Collectors.toSet()));
TreeMap<String, Set<String>> map4 = list.stream().collect(
Collectors.groupingBy(Person::getCity, TreeMap::new,
Collectors.mapping(Person::getName, Collectors.toSet())));
System.out.println(map1.getClass() + " - " + map1);
System.out.println(map2.getClass() + " - " + map2);
System.out.println(map3.getClass() + " - " + map3);
System.out.println(map4.getClass() + " - " + map4);
}
@Data
@AllArgsConstructor
private static class Person {
private String city;
private String name;
public static Person of(String city, String name) {
return new Person(city, name);
}
@Override
public String toString() {
return city + "<=" + name;
}
}
class java.util.HashMap - {上海=[上海<=李四], 深圳=[深圳<=王五, 深圳<=小红], 北京=[北京<=张三, 北京<=小明]}
class java.util.HashMap - {上海=[上海<=李四], 深圳=[深圳<=小红, 深圳<=王五], 北京=[北京<=小明, 北京<=张三]}
class java.util.TreeMap - {上海=[上海<=李四], 北京=[北京<=小明, 北京<=张三], 深圳=[深圳<=小红, 深圳<=王五]}
class java.util.TreeMap - {上海=[李四], 北京=[张三, 小明], 深圳=[王五, 小红]}
groupingByConcurrent
与 groupingBy
功能类似,但返回 ConcurrentMap
public static <T, K> Collector<T, ?, ConcurrentMap<K, List<T>>>
groupingByConcurrent(Function<? super T, ? extends K> classifier)
public static <T, K, A, D>
Collector<T, ?, ConcurrentMap<K, D>> groupingByConcurrent(
Function<? super T, ? extends K> classifier,
Collector<? super T, A, D> downstream)
public static <T, K, A, D, M extends ConcurrentMap<K, D>>
Collector<T, ?, M> groupingByConcurrent(Function<? super T, ? extends K> classifier,
Supplier<M> mapFactory,
Collector<? super T, A, D> downstream)
分区:partitioningBy
只会分成 TRUE、FALSE 两个区
// 根据 predicate 进行分区,返回值为 Map<Boolean, List<T>>
public static <T>
Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate)
// 根据 predicate 进行分区,返回值为 Map<Boolean, D>,D 是 downstream 的返回值
public static <T, D, A>
Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate,
Collector<? super T, A, D> downstream)
public static void main(String[] args) {
String[] arr = {"a", "bb", "ccc", "dddd", "eeeee"};
Map<Boolean, List<String>> map1 = Arrays.stream(arr).collect(
Collectors.partitioningBy(e -> e.length() > 2));
Map<Boolean, Set<String>> map2 = Arrays.stream(arr).collect(
Collectors.partitioningBy(e -> e.length() > 2, Collectors.toSet()));
System.out.println(map1);
System.out.println(map2);
}
{false=[a, bb], true=[ccc, dddd, eeeee]}
{false=[bb, a], true=[ccc, eeeee, dddd]}
统计信息:summarizingInt、summarizingLong、summarizingDouble
返回的统计信息包括:sum、count、average、min、max
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(Person.of("张三", 18));
list.add(Person.of("李四", 25));
list.add(Person.of("王五", 15));
IntSummaryStatistics statistics = list.stream().collect(Collectors.summarizingInt(Person::getAge));
System.out.println(statistics);
}
@Data
@AllArgsConstructor
private static class Person {
private String name;
private int age;
public static Person of(String name, int age) {
return new Person(name, age);
}
}
IntSummaryStatistics{count=3, sum=58, min=15, average=19.333333, max=25}