• java8新特性(中)-StreamAPI


    1.StreamAPI 了解

    1.1 了解Stream

    Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一个则是 Stream API(java.util.stream.*)。
    Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数
    据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。

    1.2 什么是Stream?

    流(Stream) 到底是什么呢?
    是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。“集合讲的是数据,流讲的是计算!”
    注意:
    ①Stream 自己不会存储元素。
    ②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
    ③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

    1.3 Stream 的操作三个步骤

    • 创建 Stream
      一个数据源(如:集合、数组),获取一个流
    • 中间操作
      一个中间操作链,对数据源的数据进行处理
    • 终止操作(终端操作)
      一个终止操作,执行中间操作链,并产生结果
      在这里插入图片描述

    2.创建Stream

    Java8 中的 Collection 接口被扩展,提供了两个获取流的方法:

    • default Stream stream() : 返回一个顺序流
    • default Stream parallelStream() : 返回一个并行流

    2.1 由数组创建流

    Java8 中的 Arrays 的静态方法 stream() 可以获取数组流.

    2.2 由值创建流

    可以使用静态方法 Stream.of(), 通过显示值创建一个流。它可以接收任意数量的参数。

    2.3 由函数创建流:创建无限流

    可以使用静态方法 Stream.iterate() 和Stream.generate(), 创建无限流。

    public class TestStreamAPI1 {
        //创建Stream
        @Test
        public void test1(){
            //1.可以通过Collection系列集合提供的Stream()或parallelStream()
            List<String>list=new ArrayList<>();
            Stream<String>stream1=list.stream();
    
            //2.通过Arrays中的静态方法stream()获取数组
            Employee[]emps=new Employee[10];
            Stream<Employee>stream2= Arrays.stream(emps);
    
            //3.通过Stream类中的静态方法of()
            Stream<String>stream3=Stream.of("aa","bb","cc");
    
            //4.创建无限流
            //迭代,seed是一个种子,从这个种子开始迭代
            Stream<Integer>stream4=Stream.iterate(0,(x)->x+2);
            stream4
                    .limit(10) //中间操作
                    .forEach(System.out::println);
    		//这个无限流实现了一个从0开始的,公差为2的等差数列,limit限制了输出前10个
            //生成随机数
            Stream.generate(()->Math.random())
                    .limit(5)
                    .forEach(System.out::println);
           //这个无限流实现了输出5个随机数
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    3.Stream 的中间操作

    多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”。

    3.1 筛选与切片

    3.1.1 filter–过滤流

    接收Lambda,从流中排除某些元素

    //内部迭代:迭代操作是Stream API 完成
        @Test
        public void test1(){
            //中间操作:不会执行的任何操作
            Stream<Employee>stream= employees.stream()
                    .filter((e)->{
                        System.out.println("Stream API 的中间操作");
                        return e.getAge()>35;
                    });
            //终结操作:一次性执行全部内容,即"惰性求职"
            stream.forEach(System.out::println);
        }
        //外部迭代:
        @Test
        public void test2(){
            Iterator<Employee>it=employees.iterator();
            while(it.hasNext()){
                System.out.println(it.next());
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    3.1.2 limit–截断流

    使其元素不超给定的数量

    //limit
        @Test
        public void test3(){
            employees.stream()
                    .filter((e)->e.getSalary()>5000)
                    .limit(2)
                    .forEach(System.out::println);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3.1.3 skip(n)–跳跃流

    跳过元素,返回一个扔掉了前n个元素的流.若流中元素不足n个,则返回一个空流.与Limit(n)互补

    //skip
        @Test
        public void test4(){
            employees.stream()
                    .filter((e)->e.getSalary()>5000)
                    .skip(2)
                    .forEach(System.out::println);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3.1.4 distinct–去重流

    通过流生成的元素hashCode()和equals()去除重复元素

    //distinct:注意,实体类必须重写hasCode和equals
        @Test
        public void test5(){
            employees.stream()
                    .filter((e)->e.getSalary()>2000)
                    .distinct()
                    .forEach(System.out::println);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3.2 映射

    map-接收Lambda,将元素转换成其他形式或提取信息.接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素.
    flatMap–接收一个函数作为参数,将流中的每一个值都换成另一个流,然后把所有的流连接成一个流.

    • map(Function f):接收一个函数作为参数,该函数会被应用到每个元
      素上,并将其映射成一个新的元素。
    • mapToDouble(ToDoubleFunction f):接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream。
    • mapToDouble(ToDoubleFunction f):接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 IntStream。
    • mapToLong(ToLongFunction f):接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 LongStream。
    • flatMap(Function f):接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流.
    @Test
        public void test6(){
            List<String>list=Arrays.asList("aaa","bbb","ccc","ddd","eee");
            //将所有的小写转换成大写
            list.stream()
                    .map((str)->str.toUpperCase(Locale.ROOT))
                    .forEach(System.out::println);
            System.out.println("=========================");
            //将实体的名字全部提出来,并且封装成一个集合
            employees.stream()
                    .map(Employee::getName)
                    .forEach(System.out::println);
            System.out.println("=========================");
            //调用fiterCharcter方法,将字符串拆分成字符数组
            Stream<Stream<Character>>stream=list.stream()
                    .map(TestStreamAPI2::fiterCharcter);//{{a,a,a},{b,b,b}}
    		//直接使用增强for循环输出所有值
            stream.forEach((sm)->{
                sm.forEach(System.out::println);
            });
            System.out.println("=========================");
    		//将字符串转换成字符数组,并且全部放到集合中
            Stream<Character>sm=list.stream().flatMap(TestStreamAPI2::fiterCharcter);//{a,a,a,b,b,b}
            sm.forEach(System.out::println);
    
        }
    
    	//将字符串转换成字符数组
        public static Stream<Character>fiterCharcter(String str){
            List<Character>list=new ArrayList<>();
            for (Character ch:str.toCharArray()){
                list.add(ch);
            }
            return list.stream();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    3.3 数组集合互转

    创建一个一个公用的输出类,代替system.out::println,因为他只能按照固定格式输出

    public class PrintUtil {
        /**
         * 将要遍历的数据出成一行
         */
        public void print(String x) {
            System.out.print(x + "\t");
        }
    
        public void print(Integer x) {
            System.out.print(x + "\t");
        }
    
        public void print(Long x) {
            System.out.print(x + "\t");
        }
        public void print(Object x) {
            System.out.println(x + "\t");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • stream.asList:数组转集合
    @Test
        public void test7(){
            //测试一下List集合的,add和addAll
            List<String>list=Arrays.asList("aaa","bbb","ccc","ddd","eee");
            List list2=new ArrayList();
            list2.add(11);
            list2.add(12);
            list2.add(list);
            list2.forEach(System.out::println);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    输出结果:

    11	12	[aaa, bbb, ccc, ddd, eee]	
    
    • 1
    • list.stream().toArray(T []:new):集合转数组
    @Test
        public void test9(){
            List<Integer> list = new ArrayList<>();
            list.add(1);
            list.add(3);
            list.add(5);
            list.add(7);
    
            Integer[] intArray = list.stream().toArray(Integer[]::new);
            //Arrays.stream(intArray).forEach(System.out::println);
            Arrays.stream(intArray).forEach(new PrintUtil()::print);
            System.out.println();
    
            //将其转换为long数组,由于int与long类型不一致,如果直接按上面这种形式转换,会出现转换错误,需要先使用map()把元素类型强转为long
            Long[] longArray = list.stream().map(el->(long)el).toArray(Long[]::new);
            Arrays.stream(longArray).forEach(new PrintUtil()::print);
            System.out.println();
    
            //将其转换为String数组【与转换为long同理】
            String[]strArray=list.stream().map(el->String.valueOf(el)).toArray(String[]::new);
            Arrays.stream(strArray).forEach(new PrintUtil()::print);
            System.out.println();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    输出结果

    1	3	5	7	
    1	3	5	7	
    1	3	5	7	
    
    • 1
    • 2
    • 3

    3.4 排序

    先创建一个实体类型的集合,以便进行下面的实验

    List<Employee> employees = Arrays.asList(
                new Employee("张三", 18, 99999.9),
                new Employee("李四", 29, 99499.9),
                new Employee("王五", 22, 1999.9),
                new Employee("赵六", 26, 12999.9),
                new Employee("赵六", 26, 12999.9),
                new Employee("赵六", 26, 12999.9),
                new Employee("钱七", 38, 3999.9)
        );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • sorted():产生一个新流,其中按自然顺序排序
    • sorted(Comparator comp):产生一个新流,其中按比较器顺序排序
    @Test
        public void test8(){
            System.out.println("------------------自然排序---------------------");
            List<String>list=Arrays.asList("ccc","aaa","bbb","ddd","eee");
            list.stream()
                    .sorted()
                    .forEach(System.out::println);
            System.out.println("------------------定制排序---------------------");
            employees.stream().sorted((e1,e2)->{
                if(e1.getAge()==e2.getAge()){
                    return e2.getName().compareTo(e2.getName());
                }else{
                    return Integer.compare(e1.getAge(),e2.getAge());
                }
            }).forEach(System.out::println);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    4.Stream 的终止操作

    终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List、Integer,甚至是 void 。

    实体类集合

    先创建一个实体类型的集合,以便进行下面的实验

    List<Employee> emps = Arrays.asList(
                new Employee(102, "李四", 79, 6666.66, Status.BUSY),
                new Employee(101, "张三", 18, 9999.99, Status.FREE),
                new Employee(103, "王五", 28, 3333.33, Status.VOCATION),
                new Employee(104, "赵六", 8, 7777.77, Status.BUSY),
                new Employee(104, "赵六", 8, 7777.77, Status.FREE),
                new Employee(104, "赵六", 8, 7777.77, Status.FREE),
                new Employee(105, "田七", 38, 5555.55, Status.BUSY)
        );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    4.1 匹配

    allMatch——检查是否匹配所有元素

    	 	//allMatch——检查是否匹配所有元素
          	System.out.println("===============allMatch=================");
            boolean b1 = emps.stream().allMatch((e) -> e.getStatus().equals(Status.BUSY));
            System.out.println(b1);
    
    • 1
    • 2
    • 3
    • 4

    anyMatch—检查是否至少匹配一个元素

    		//anyMatch—检查是否至少匹配一个元素
            System.out.println("===============anyMatch=================");
            boolean b2 = emps.stream().anyMatch((e) -> e.getStatus().equals(Status.BUSY));
            System.out.println(b2);
    
    • 1
    • 2
    • 3
    • 4

    noneMatch—检查是否没有匹配所有元素

    		//noneMatch—检查是否没有匹配所有元素
            System.out.println("===============noneMatch=================");
            boolean b3 = emps.stream().noneMatch((e) -> e.getStatus().equals(Status.BUSY));
            System.out.println(b3);
    
    • 1
    • 2
    • 3
    • 4

    findFirst——返回第一个元素

    		//findFirst——返回第一个元素
            System.out.println("===============findFirst=================");
            //Optional可以防止返回值为空
            Optional<Employee> op = emps.stream().sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())).findFirst();
            System.out.println(op.get());
    
    • 1
    • 2
    • 3
    • 4
    • 5

    findAny—返回当前流中的任意元素

    		//findAny—返回当前流中的任意元素
            System.out.println("===============findAny=================");
            //parallelStream()是多线程流
            Optional<Employee> op2 = emps.parallelStream().filter((e) -> e.getStatus().equals(Status.FREE)).findAny();
            System.out.println(op2.get());
    
    • 1
    • 2
    • 3
    • 4
    • 5

    完整代码

    @Test
        public void test1() {
            //allMatch——检查是否匹配所有元素
            System.out.println("===============allMatch=================");
            boolean b1 = emps.stream().allMatch((e) -> e.getStatus().equals(Status.BUSY));
            System.out.println(b1);
    
            //anyMatch—检查是否至少匹配一个元素
            System.out.println("===============anyMatch=================");
            boolean b2 = emps.stream().anyMatch((e) -> e.getStatus().equals(Status.BUSY));
            System.out.println(b2);
    
            //noneMatch—检查是否没有匹配所有元素
            System.out.println("===============noneMatch=================");
            boolean b3 = emps.stream().noneMatch((e) -> e.getStatus().equals(Status.BUSY));
            System.out.println(b3);
    
            //findFirst——返回第一个元素
            System.out.println("===============findFirst=================");
            //Optional可以防止返回值为空
            Optional<Employee> op = emps.stream().sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())).findFirst();
            System.out.println(op.get());
    
            //findAny—返回当前流中的任意元素
            System.out.println("===============findAny=================");
            //parallelStream()是多线程流
            Optional<Employee> op2 = emps.parallelStream().filter((e) -> e.getStatus().equals(Status.FREE)).findAny();
            System.out.println(op2.get());
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    4.2 查找

    count——返回流中元素的总个数

    		//count——返回流中元素的总个数
            System.out.println("==================count==================");
            Long count = emps.stream().count();
            System.out.println(count);
    
    • 1
    • 2
    • 3
    • 4

    max——返回流中最大值

    		//max——返回流中最大值
            System.out.println("==================max==================");
            Optional<Employee> op1 = emps.stream().max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
            System.out.println(op1.get());
    
    • 1
    • 2
    • 3
    • 4

    min——返回流中最小值

    		//min——返回流中最小值
            System.out.println("==================min==================");
            Optional<Double> op2 = emps.stream().map(Employee::getSalary).min(Double::compare);
            System.out.println(op2.get());
    
    • 1
    • 2
    • 3
    • 4

    完整代码

     @Test
        public void test2() {
            //count——返回流中元素的总个数
            System.out.println("==================count==================");
            Long count = emps.stream().count();
            System.out.println(count);
    
            //max——返回流中最大值
            System.out.println("==================max==================");
            Optional<Employee> op1 = emps.stream().max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
            System.out.println(op1.get());
    
            //min——返回流中最小值
            System.out.println("==================min==================");
            Optional<Double> op2 = emps.stream().map(Employee::getSalary).min(Double::compare);
            System.out.println(op2.get());
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    4.3 归约

    reduce(T iden, BinaryOperator b) :可以将流中元素反复结合起来,得到一个值。返回 T

    		List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
            Integer sum = list.stream().reduce(0, (x, y) -> x + y);
            System.out.println(sum)
    
    • 1
    • 2
    • 3

    reduce(BinaryOperator b):可以将流中元素反复结合起来,得到一个值。返回 Optional

    		Optional<Double> op = emps.stream().map(Employee::getSalary).reduce(Double::sum);
            System.out.println(op.get());
    
    • 1
    • 2

    完整代码

    //归约
        @Test
        public void test3() {
            //reduce(T identity,Binaryoperation)/reduce(BinaryOperation)--可以将流中元素反复结合起来,得到一个值
            List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
            Integer sum = list.stream().reduce(0, (x, y) -> x + y);
            System.out.println(sum);
            System.out.println("================================");
            Optional<Double> op = emps.stream().map(Employee::getSalary).reduce(Double::sum);
            System.out.println(op.get());
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    4.4 收集-转换成集合

    collect(Collector c):将流转换为其他形式。接收一个 Collector接口的
    实现,用于给Stream中元素做汇总的方法
    Collector 接口中方法的实现决定了如何对流执行收集操作(如收集到 List、Set、Map)。但是 Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下表:

    4.4.1 toList:把流中元素收集到List

    		List<String> list = emps.stream().map(Employee::getName).collect(Collectors.toList());
            list.forEach(System.out::println);
    
    • 1
    • 2

    4.4.2 toSet :把流中元素收集到Set

    		Set<String> set = emps.stream().map(Employee::getName).collect(Collectors.toSet());
            System.out.println(set);
    
    • 1
    • 2

    4.4.3 toCollection: 把流中元素收集到创建的集合

    		HashSet<String> hs = emps.stream().map(Employee::getName).collect(Collectors.toCollection(HashSet::new));
            hs.forEach(System.out::println);
    
    • 1
    • 2

    完整代码

    @Test
        public void test4() {
            List<String> list = emps.stream().map(Employee::getName).collect(Collectors.toList());
            list.forEach(System.out::println);
    
            System.out.println("===============================");
            Set<String> set = emps.stream().map(Employee::getName).collect(Collectors.toSet());
            System.out.println(set);
    
            System.out.println("===========================");
            HashSet<String> hs = emps.stream().map(Employee::getName).collect(Collectors.toCollection(HashSet::new));
            hs.forEach(System.out::println);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    4.5 收集-汇总计算

    4.5.1 counting:计算流中有多少个元素

    		//计算元素的个数:
    		Long count = emps.stream().collect(Collectors.counting());
            System.out.println(count);//
    
    • 1
    • 2
    • 3

    4.5.2 summingInt:计算流中所有Integer类型的元素之和

    Integer sumage=emps.stream().collect(Collectors.summingInt(Employee::getAge));
            System.out.println(sumage);//187
    
    • 1
    • 2

    4.5.3 averagingInt:对流中元素的所有整数属性求平均值,返回值为浮点型

    		Double averageage = emps.stream().collect(Collectors.averagingInt(Employee::getAge));
            System.out.println(averageage);//26.714285714285715
    
    • 1
    • 2

    4.5.4 summarizingInt:统计流中所有Int类型的元素的最大值,最小值,总和,平均值

    		IntSummaryStatistics averageage= emps.stream().collect(Collectors.summarizingInt(Employee::getAge));
            System.out.println(averageage);//IntSummaryStatistics{count=7, sum=187, min=8, average=26.714286, max=79}
    
    • 1
    • 2

    这些方法还可以求:Double,Long型的数据
    完整代码:

     @Test
        public void test5() {
           //总数
            Long count = emps.stream().collect(Collectors.counting());
            System.out.println(count);//7
            System.out.println("=====================================");
    
            //summingInt:整型求和
            Integer sumage = emps.stream().collect(Collectors.summingInt(Employee::getAge));
            System.out.println(sumage);//187
            System.out.println("=====================================");
    
            //averagingInt:整型求平均值,返回值是Double类型
            Double averageage = emps.stream().collect(Collectors.averagingInt(Employee::getAge));
            System.out.println(averageage);//26.714285714285715
            System.out.println("=====================================");
    
            //summarizingInt:整型统计
            IntSummaryStatistics statisticsage = emps.stream().collect(Collectors.summarizingInt(Employee::getAge));
            System.out.println(statisticsage);//IntSummaryStatistics{count=7, sum=187, min=8, average=26.714286, max=79}
            System.out.println("=====================================");
    
            //summingDouble:浮点型求和
            Double sumsalary = emps.stream().collect(Collectors.summingDouble(Employee::getSalary));
            System.out.println(sumsalary);//48888.840000000004
            System.out.println("=====================================");
    
            //averagingDouble:浮点型求平均值
            Double avgsalary = emps.stream().collect(Collectors.averagingDouble(Employee::getSalary));
            System.out.println(avgsalary);//6984.120000000001
            System.out.println("=====================================");
    
            //summarizingDouble:浮点型统计
            DoubleSummaryStatistics statisticssalary= emps.stream().collect(Collectors.summarizingDouble(Employee::getSalary));
            System.out.println(statisticssalary);//DoubleSummaryStatistics{count=7, sum=48888.840000, min=3333.330000, average=6984.120000, max=9999.990000}
            System.out.println("=====================================");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    4.6 收集-最值

    使用下面方法如果有很多个相同的值,则返回的是第一个值

    4.6.1 maxBy:求最大值

    		Optional<Employee> max = emps.stream().collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
            System.out.println(max.get());//Employee(id=101, name=张三, age=18, salary=9999.99, status=FREE)
    
    • 1
    • 2

    4.6.2 minBy:求最小值

    		Optional<Employee> min = emps.stream().collect(Collectors.minBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
            System.out.println(min.get());//Employee(id=103, name=王五, age=28, salary=3333.33, status=VOCATION)
    
    • 1
    • 2

    完整代码:

    public void test(){
    //求薪水最高的人
            Optional<Employee> max = emps.stream().collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
            System.out.println(max.get());//Employee(id=101, name=张三, age=18, salary=9999.99, status=FREE)
            System.out.println("=====================================");
    
            //求薪水最低的人
            Optional<Employee> min = emps.stream().collect(Collectors.minBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
            System.out.println(min.get());//Employee(id=103, name=王五, age=28, salary=3333.33, status=VOCATION)
            System.out.println("=====================================");
    
            //求年龄最小的人
            Optional<Employee> minAge = emps.stream().collect(Collectors.minBy((e1, e2) -> Integer.compare(e1.getAge(), e2.getAge())));
            System.out.println(minAge.get());//Employee(id=104, name=赵六, age=8, salary=7777.77, status=BUSY)
            System.out.println("=====================================");
    
            //求最小的年龄值
            Optional<Integer> op = emps.stream().map(Employee::getAge).collect(Collectors.minBy((e1, e2) -> Integer.compare((Integer) e1, (Integer)e2)));
            System.out.println(op.get());//8
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    4.7 分组

    4.7.1 单级分组

     @Test
        public void test6() {
            Map<Status, List<Employee>> map = emps.stream().collect(Collectors.groupingBy(Employee::getStatus));
            Set<Status> set = map.keySet();
            set.forEach((e) -> {
                System.out.println(e+":");
                map.get(e).forEach(System.out::println);
            });
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    输出结果

    FREE:
    Employee(id=101, name=张三, age=18, salary=9999.99, status=FREE)
    Employee(id=104, name=赵六, age=8, salary=7777.77, status=FREE)
    Employee(id=104, name=赵六, age=8, salary=7777.77, status=FREE)
    VOCATION:
    Employee(id=103, name=王五, age=28, salary=3333.33, status=VOCATION)
    BUSY:
    Employee(id=102, name=李四, age=79, salary=6666.66, status=BUSY)
    Employee(id=104, name=赵六, age=8, salary=7777.77, status=BUSY)
    Employee(id=105, name=田七, age=38, salary=5555.55, status=BUSY)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    4.7.2 多级分组

    //先按照状态分组,然后再按照年龄分组
     @Test
        public void test7() {
            Map<Status, Map<String, List<Employee>>> map = emps.stream()
                    .collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
                        if (((Employee) e).getAge() <= 35) {
                            return "青年";
                        } else if (((Employee) e).getAge() <= 50) {
                            return "中年";
                        } else {
                            return "老年";
                        }
                    })));
            //输出
            Set<Status> set = map.keySet();
            set.forEach((e) -> {
                Set<String> ageset = map.get(e).keySet();
                ageset.forEach(
                        (x)->{
                            System.out.println(e+"-"+x+":");
                            map.get(e).get(x).forEach(System.out::println);
                        }
                );
                System.out.println("=================================");
            });
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    输出结果

    BUSY-青年:
    Employee(id=104, name=赵六, age=8, salary=7777.77, status=BUSY)
    BUSY-老年:
    Employee(id=102, name=李四, age=79, salary=6666.66, status=BUSY)
    BUSY-中年:
    Employee(id=105, name=田七, age=38, salary=5555.55, status=BUSY)
    =================================
    FREE-青年:
    Employee(id=101, name=张三, age=18, salary=9999.99, status=FREE)
    Employee(id=104, name=赵六, age=8, salary=7777.77, status=FREE)
    Employee(id=104, name=赵六, age=8, salary=7777.77, status=FREE)
    =================================
    VOCATION-青年:
    Employee(id=103, name=王五, age=28, salary=3333.33, status=VOCATION)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    4.6 分区

    partitioningBy:根据boolean条件进行分区

    //将薪水大于5000的分为一组,小于等于5000的分为一组
    @Test
        public void test8() {
            Map<Boolean, List<Employee>> map = emps.stream()
                    .collect(Collectors.partitioningBy(e -> e.getSalary() > 5000));
            //输出
            Set<Boolean> set = map.keySet();
            set.forEach(y -> {
                System.out.println(y);
                map.get(y).forEach(System.out::println);
            });
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    输出结果

    false
    Employee(id=103, name=王五, age=28, salary=3333.33, status=VOCATION)
    true
    Employee(id=102, name=李四, age=79, salary=6666.66, status=BUSY)
    Employee(id=101, name=张三, age=18, salary=9999.99, status=FREE)
    Employee(id=104, name=赵六, age=8, salary=7777.77, status=BUSY)
    Employee(id=104, name=赵六, age=8, salary=7777.77, status=FREE)
    Employee(id=104, name=赵六, age=8, salary=7777.77, status=FREE)
    Employee(id=105, name=田七, age=38, salary=5555.55, status=BUSY)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  • 相关阅读:
    电压基准源
    Python大数据之Python进阶(二)多任务编程-进程
    C++常用格式化输出转换
    java毕业设计藏宝阁游戏交易系统Mybatis+系统+数据库+调试部署
    Java SpringBoot实现PDF转图片
    Linux 安全 - LSM源码分析
    初入编程之门的个人建议1.0
    【故障公告】1个存储过程拖垮整个数据库
    c语言-手撕多级时间轮定时器(纯手写)
    抓住那头牛——BFS
  • 原文地址:https://blog.csdn.net/qq_35653657/article/details/126773322