Collectors 中的各种方法

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}

参考

  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值