collect

分组和分区

public class StreamTest04 {
    public static void main(String[] args) {
        List<String> list1 = Arrays.asList("hi", "hello", "你好");
        List<String> list2 = Arrays.asList("张三", "李四", "王五");
        List<String> collect = list1.stream().flatMap(l1 -> list2.stream().map(l2 -> l1 + ":" + l2)).collect(Collectors.toList());
        collect.stream().forEach(System.out::println);
       //  hi:张三
       //  hi:李四
       //  hi:王五
       //  hello:张三
       //  hello:李四
       //  hello:王五
       //  你好:张三
       //  你好:李四
       //  你好:王五

        //  ------------1.按年龄分组,并返回每组总数----------------
        List<User> users=Arrays.asList(
                new User("tom",11,87),
                new User("jim",11,88),
                new User("join",12,90),
                new User("tax",13,78)
        );

        Map<Integer, Long> fzOne = users.stream().collect(Collectors.groupingBy(e -> e.getAge(), Collectors.counting()));
        System.out.println(fzOne);
        //{11=2, 12=1, 13=1}

        //  ------------2.按年龄分组,并返回每组的分数平均值----------------
        Map<Integer, Double> fzTwo= users.stream().collect(Collectors.groupingBy(e -> e.getAge(), Collectors.averagingDouble(User::getScore)));
        System.out.println(fzTwo);
        //{11=87.5, 12=90.0, 13=78.0}

    }
    
}

分区: 分区(partitioningBy)可以看成是一种特殊的分组 ,分区只能分为两组 ,即成立某种条件的和不成立某种条件的

//  ------------按照成绩是否大于90分组----------------
     List<User> userList =Arrays.asList(
             new User("tom",11,87),
             new User("jim",11,98),
             new User("join",12,90),
             new User("tax",13,78)
     );
     Map<Boolean, List<User>> c1 = userList.stream().collect(Collectors.partitioningBy(e -> e.getScore() >= 90));
     System.out.println(c1);
     //{
     // false=[User(name=tom, age=11, score=87), User(name=tax, age=13, score=78)],
     // true =[User(name=jim, age=11, score=98), User(name=join, age=12, score=90)]
     // }
     Map<Boolean, Long> c2 = userList.stream().collect(Collectors.partitioningBy(e -> e.getScore() >= 90, Collectors.counting()));
     System.out.println(c2);
     //{false=2, true=2}

收集器:collect

Collector是专门用来作为Stream的collect方法的参数的。 而Collectors是作为生产具体Collector的工具类。

Collector主要包含五个参数,它的行为也是由这五个参数来定义的,如下所示:

public interface Collector<T, A, R> {
    // supplier参数用于生成结果容器,容器类型为A
    Supplier<A> supplier();
    // accumulator用于消费元素,也就是归纳元素,这里的T就是元素,它会将流中的元素一个一个与结果容器A发生操作
    BiConsumer<A, T> accumulator();
    // combiner用于两个两个合并并行执行的线程的执行结果,将其合并为一个最终结果A
    BinaryOperator<A> combiner();
    // finisher用于将之前整合完的结果R转换成为A
    Function<A, R> finisher();
    // characteristics表示当前Collector的特征值,这是个不可变Set
    Set<Characteristics> characteristics();
}

Collectors是一个工具类,是JDK预实现Collector的工具类,它内部提供了多种Collector,如:

toCollection

将流中的元素全部放置到一个集合中返回,这里使用Collection,泛指多种集合。

toSet

将流中的元素放置到一个列表集合中去。这个列表默认为ArrayList。

joining

joining的目的是将流中的元素全部以字符序列的方式连接到一起,可以指定连接符,甚至是结果的前后缀。

public class CollectorsTest {
    public static void joiningTest(List<String> list){
        // 无参方法
        String s = list.stream().collect(Collectors.joining());
        System.out.println(s);
        // 指定连接符
        String ss = list.stream().collect(Collectors.joining("-"));
        System.out.println(ss);
        // 指定连接符和前后缀
        String sss = list.stream().collect(Collectors.joining("-","S","E"));
        System.out.println(sss);
    }
    public static void main(String[] args) {
        List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");
        joiningTest(list);
    }
}

console:
1234567891101212121121asdaa3e3e3e2321eew
123-456-789-1101-212121121-asdaa-3e3e3e-2321eew
S123-456-789-1101-212121121-asdaa-3e3e3e-2321eewE

mapping

这个映射是首先对流中的每个元素进行映射,即类型转换,然后再将新元素以给定的Collector进行归纳。

public class CollectorsTest {
    public static void mapingTest(List<String> list){
        List<Integer> ll = list.stream().limit(5).collect(Collectors.mapping(Integer::valueOf,Collectors.toList()));
    }
    public static void main(String[] args) {
        List<String> list = Arrays.asList("123","456","789","1101","111","asdaa","3e3e3e","2321eew");
        mapingTest(list);
    }
}

collectingAndThen

该方法是在归纳动作结束之后,对归纳的结果进行再处理。

public class CollectorsTest {
    public static void collectingAndThenTest(List<String> list){
        int length = list.stream().collect(Collectors.collectingAndThen(Collectors.toList(),e -> e.size()));
        System.out.println(length);
    }
    public static void main(String[] args) {
        List<String> list = Arrays.asList("123","456","789");
        collectingAndThenTest(list);
    }
}

等等………

多级分组

//  ------------按照成绩是否大于90分组----------------
        List<User> userList =Arrays.asList(
                new User("tom",11,87),
                new User("jim",11,98),
                new User("join",12,90),
                new User("tax",13,90)
        );

        // 先按照成绩分组,在按照年龄分组:
        Map<Integer, Map<Integer, List<User>>> cc = userList.stream().collect(Collectors.groupingBy(User::getScore, Collectors.groupingBy(User::getAge)));
        System.out.println(cc);

console:
{
    98={11=[User(name=jim, age=11, score=98)]},
    87={11=[User(name=tom, age=11, score=87)]},
    90={
        12=[User(name=join, age=12, score=90)], 
        13=[User(name=tax, age=13, score=90)]
       }
}
//先按照年龄分组,再求分数最高的
        Map<Integer, User> ccc = userList.stream().collect(Collectors.groupingBy(User::getAge, Collectors.collectingAndThen(Collectors.maxBy(Comparator.comparingInt(User::getScore)), Optional::get)));
        System.out.println(ccc);


console:

{
    11=User(name=jim, age=11, score=98),
    12=User(name=join, age=12, score=90),
    13=User(name=tax, age=13, score=90)
}