java 1.8 stream 应用-22种案例

java 1.8 stream 22中应用案例

1. stream简介

java 1.8版本更新的一个亮点Stream,给开发者对集合(Collection)的操作提供了极大的便利。
特性

  1. stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果。
  2. stream不会改变数据源,通常情况下会产生一个新的集合或一个值

2. 案例

案例有简单到复杂

2.1 数据准备

学生 Student

public class Student {

    /**
     * 年龄
     */
    private int age;

    /**
     * 姓名
     */
    private String name;

    /**
     * 成绩
     */
    private int fraction;

    /**
     * 性别
     */
    private String sex;

    /**
     * 老师id
     */
    private String teaId;

    public Student(int age, String name, int fraction, String sex) {
        this.age = age;
        this.name = name;
        this.fraction = fraction;
        this.sex = sex;
    }

    public Student(int age, String name, int fraction, String sex, String teaId) {
        this.age = age;
        this.name = name;
        this.fraction = fraction;
        this.sex = sex;
        this.teaId = teaId;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getFraction() {
        return fraction;
    }

    public void setFraction(int fraction) {
        this.fraction = fraction;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public void addFraction() {
        this.fraction++;
    }

    public String getTeaId() {
        return teaId;
    }

    public void setTeaId(String teaId) {
        this.teaId = teaId;
    }


    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", fraction=" + fraction +
                ", sex='" + sex + '\'' +
                ", teaId='" + teaId + '\'' +
                '}';
    }
}

教师 Teacher

public class Teacher {

    private String id;

    private String name;

    public Teacher(String id, String name) {
        this.id = id;
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

初始化数据

     public static List<Student> getStudents() {
        List<Student> studentList = new ArrayList<>();
        studentList.add(new Student(18, "A18", 60, "man", "1"));
        studentList.add(new Student(17, "A17", 50, "woman","1"));
        studentList.add(new Student(19, "A19", 80, "man","3"));
        studentList.add(new Student(20, "A20", 90, "woman", "2"));
        studentList.add(new Student(25, "A25", 40, "man", "1"));
        studentList.add(new Student(15, "A15", 92, "man", "3"));
        studentList.add(new Student(16, "A16", 92, "woman", "1"));
        return studentList;
    }

    public static List<Student> getStudents2() {
        List<Student> studentList = new ArrayList<>();
        studentList.add(new Student(18, "B18", 60, "man", "6"));
        studentList.add(new Student(17, "B17", 50, "woman", "6"));
        studentList.add(new Student(20, "B17", 50, "woman", "6"));
        studentList.add(new Student(18, "B19", 80, "man", "6"));
        return studentList;
    }

    public static List<Teacher> getTeacher() {
        List<Teacher> teacherList = new ArrayList<>();
        teacherList.add(new Teacher("1", "teacher"));
        teacherList.add(new Teacher("3", "teacher"));
        return teacherList;
    }

2.2 遍历/过滤/匹配/筛选(foreach/filter/match/find)

2.2.1 遍历 foreach
test() {
	 List<Student> students = getStudents();
	 // 遍历输出方式1
	 students.stream().forEach(System.out::println);
	 System.out.println("==============================");
	 // 遍历输出方式2
	 students.stream().forEach(s -> {
	    // 在当前方法,可以对当前对象的引用进行操作
	    s.addFraction();
	    System.out.println(s.toString());
	 });
}

输出

Student{age=18, name='s18', fraction=60, sex='man'}
Student{age=17, name='A17', fraction=50, sex='man'}
Student{age=19, name='A19', fraction=80, sex='man'}
Student{age=20, name='A20', fraction=90, sex='man'}
Student{age=25, name='A25', fraction=40, sex='man'}
Student{age=15, name='A15', fraction=92, sex='man'}
==============================
Student{age=18, name='s18', fraction=61, sex='man'}
Student{age=17, name='A17', fraction=51, sex='man'}
Student{age=19, name='A19', fraction=81, sex='man'}
Student{age=20, name='A20', fraction=91, sex='man'}
Student{age=25, name='A25', fraction=41, sex='man'}
Student{age=15, name='A15', fraction=93, sex='man'}
2.2.2 过滤 filter
test() {
        // 获取数据集
        List<Student> students = getStudents();
        // 过滤年龄>=18,并遍历输出
        students.stream().filter(s -> s.getAge() >= 18).forEach(System.out::println);
 }

输出

Student{age=18, name='s18', fraction=60, sex='man'}
Student{age=19, name='A19', fraction=80, sex='man'}
Student{age=20, name='A20', fraction=90, sex='man'}
Student{age=25, name='A25', fraction=40, sex='man'}
2.2.3 匹配 match
test() {
        List<Student> students = getStudents();
        // 判断是否存在年龄大于18
        boolean anyMatch = students.stream().anyMatch(s -> s.getAge() > 18);
        System.out.println(anyMatch);

        // 判断所有的学生,年龄是否均大于18
        boolean allMatch = students.stream().allMatch(s -> s.getAge() > 20);
        System.out.println(allMatch);

        // 判断当前学生,年龄是否不存在小于8
        boolean noneMatch = students.stream().noneMatch(s -> s.getAge() < 8);
        System.out.println(noneMatch);
 }

输出

true
false
true
2.2.4 筛选 find
test() {
		List<Student> students = getStudents();
        // 筛选第一个
        Optional<Student> first = students.stream().findFirst();
        // 任意筛选一个
        Optional<Student> any = students.parallelStream().findAny();

		// .isPresent():判断是否有获取到结果对象
        if (first.isPresent()) {
            // 始终返回第一个索引数据
            System.out.println(first.get());
        }

        if(any.isPresent()) {
            // 多次测试,同一组数据,返回的结果一致
            System.out.println(any.get());
        }
}        

输出

Student{age=18, name='s18', fraction=60, sex='man'}
Student{age=25, name='A25', fraction=40, sex='man'}

说明:
stream与parallelStream区别

  • stream:顺序流,处理顺序按原List的顺序逐个执行;对数据处理先后顺序有严格要求,用顺序流,执行效率较低。
  • parallelStream:并行流,对数据分批并行处理(不会存在重复消费处理的问题),可以理解为多线程处理;对数据处理无先后顺序,可以用并行流,执行效率高。
2.2.4 过滤并形成新的集合
test() {
		List<Student> students = getStudents();
        // 过滤年龄>=18 且 成绩 >= 80学生,并形成新的集合
        // 方式1 List<Student> collect = students.stream().filter(s -> s.getAge() >= 18 && s.getFraction() >= 80).collect(Collectors.toList());
        // 方式2 自定义方法
        List<Student> collect = students.stream().filter(s -> {
            return s.getAge() >= 18 && s.getFraction() >= 80;
        }).collect(Collectors.toList());
        System.out.println(collect.toString());
 }

输出

[Student{age=19, name='A19', fraction=80, sex='man'}, Student{age=20, name='A20', fraction=90, sex='woman'}]

2.3 聚合(max/min/count)

2.3.1 获取最大值
test() {
        List<Student> students = getStudents();
        // 获取年龄最大学生
        Optional<Student> maxAge = students.stream().max(Comparator.comparing(Student::getAge));
        System.out.println(maxAge.get());
        // 获取成绩最大的学生
        Optional<Student> maxFraction = students.stream().max(Comparator.comparing(Student::getFraction));
        System.out.println(maxFraction.get());
}

输出

Student{age=25, name='A25', fraction=40, sex='man'}
Student{age=15, name='A15', fraction=92, sex='man'}
2.3.2 获取最小值
test() {
        List<Student> students = getStudents();
        // 获取年龄最小学生
        Optional<Student> minAge = students.stream().min(Comparator.comparing(Student::getAge));
        System.out.println("年龄最小学生" + minAge.get());
        // 获取成绩最差的学生
        Optional<Student> minFraction = students.stream().min(Comparator.comparing(Student::getFraction));
        System.out.println("成绩最差的学生" + minFraction.get());
}

输出

年龄最小学生Student{age=15, name='A15', fraction=92, sex='man'}
成绩最差的学生Student{age=25, name='A25', fraction=40, sex='man'}
2.3.3 过滤+汇总count
test() {
        List<Student> students = getStudents();
        // 总条数
        long count = students.stream().count();
        System.out.println("总条数:" + count);
        // 汇总年龄>18 且 成绩>80的学生个数
        long count1 = students.stream().filter(s -> s.getAge() > 18 && s.getFraction() > 80).count();
       System.out.println("年龄>18 且 成绩>80的学生个数:" + count1);
 }

输出

总条数:7
年龄>18 且 成绩>80的学生个数:1

2.4 映射(map/flatMap)

映射:可以将一个流的元素按照一定的映射规则映射到另一个流中
map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。

2.4.1 map
test() {
		List<Student> students = getStudents();
        // 映射出学生的名字,并打印输出
        students.stream().map(Student::getName).forEach(System.out::println);
        // 每位学生的年纪+1,改变原集合中的数据
        students.stream().map(stu -> {
            stu.setAge(stu.getAge() + 1);
            return stu;
        }).forEach(System.out::println);
}

输出

[s18, A17, A19, A20, A25, A15, A16]
Student{age=19, name='s18', fraction=60, sex='man'}
Student{age=18, name='A17', fraction=50, sex='woman'}
Student{age=20, name='A19', fraction=80, sex='man'}
Student{age=21, name='A20', fraction=90, sex='woman'}
Student{age=26, name='A25', fraction=40, sex='man'}
Student{age=16, name='A15', fraction=92, sex='man'}
Student{age=17, name='A16', fraction=92, sex='woman'}
2.4.2 flatMap

看一下flatMap方法定义:

<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);

参数是一个Function函数式接口,提供T到Stram的转换。其实参考方法实现,flatMap就是将Function转化后的Stram合并成一个Stream。

2.4.2.1 合并 + 获取交集
test() {
 		List<Student> students1 = getStudents();
        List<Student> students2 = getStudents2();
        Student student = new Student(99, "99", 60, "man", "99");
        students1.add(student);
        students2.add(student);
        // 1.将两个流合并在一起
        // 方式1 flatMap中的返回的参数必须是stream流
        List<Student> collect = Stream.of(students1, students2).flatMap(Collection::stream).collect(Collectors.toList());
        // 方式2
        List<Student> collect1 = Stream.of(students1, students2).flatMap(list -> list.stream()).collect(Collectors.toList());
        System.out.println(collect.size());
        System.out.println(collect1.size());
        // 2 取交集
        List<Student> collect2 = students1.stream().filter(s -> students2.contains(s)).collect(Collectors.toList());
        System.out.println(collect2.toString());
 }

输出

并集:[Student{age=18, name='A18', fraction=60, sex='man', teaId='1'}, Student{age=17, name='A17', fraction=50, sex='woman', teaId='1'}, Student{age=19, name='A19', fraction=80, sex='man', teaId='3'}, Student{age=20, name='A20', fraction=90, sex='woman', teaId='2'}, Student{age=25, name='A25', fraction=40, sex='man', teaId='1'}, Student{age=15, name='A15', fraction=92, sex='man', teaId='3'}, Student{age=16, name='A16', fraction=92, sex='woman', teaId='1'}, Student{age=99, name='99', fraction=60, sex='man', teaId='99'}, Student{age=18, name='B18', fraction=60, sex='man', teaId='6'}, Student{age=17, name='B17', fraction=50, sex='woman', teaId='6'}, Student{age=20, name='B17', fraction=50, sex='woman', teaId='6'}, Student{age=18, name='B19', fraction=80, sex='man', teaId='6'}, Student{age=99, name='99', fraction=60, sex='man', teaId='99'}]
并集:[Student{age=18, name='A18', fraction=60, sex='man', teaId='1'}, Student{age=17, name='A17', fraction=50, sex='woman', teaId='1'}, Student{age=19, name='A19', fraction=80, sex='man', teaId='3'}, Student{age=20, name='A20', fraction=90, sex='woman', teaId='2'}, Student{age=25, name='A25', fraction=40, sex='man', teaId='1'}, Student{age=15, name='A15', fraction=92, sex='man', teaId='3'}, Student{age=16, name='A16', fraction=92, sex='woman', teaId='1'}, Student{age=99, name='99', fraction=60, sex='man', teaId='99'}, Student{age=18, name='B18', fraction=60, sex='man', teaId='6'}, Student{age=17, name='B17', fraction=50, sex='woman', teaId='6'}, Student{age=20, name='B17', fraction=50, sex='woman', teaId='6'}, Student{age=18, name='B19', fraction=80, sex='man', teaId='6'}, Student{age=99, name='99', fraction=60, sex='man', teaId='99'}]
交集:[Student{age=99, name='99', fraction=60, sex='man', teaId='99'}]
2.4.2.2 多集合获取关联数据

一批教师:teacher
一班学生:students1
二班学生:students2
复杂,获取指定教师下的学生, 转Map<teaId, List>

test() {
		List<Student> students1 = getStudents();
        List<Student> students2 = getStudents2();
        List<Teacher> teachers = getTeacher();
        Student student = new Student(99, "99", 60, "man", "99");
        students1.add(student);
        students2.add(student);
        Map<String, List<Student>> collect3 = teachers.stream()
        		 // 难理解的点:合并所有学生,并过滤筛选出这批教师下的学生
                .flatMap(tea -> Stream.of(students1, students2)
                						.flatMap(Collection::stream)
                						.filter(stu -> stu.getTeaId().equals(tea.getId()))
                	 	)
                 // 最终获取这批教师下的学生流集合,分组
                .collect(Collectors.groupingBy(Student::getTeaId));

        for (String key: collect3.keySet()) {
            System.out.println(collect3.get(key));
        }
}

输出

[Student{age=18, name='A18', fraction=60, sex='man', teaId='1'}, Student{age=17, name='A17', fraction=50, sex='woman', teaId='1'}, Student{age=25, name='A25', fraction=40, sex='man', teaId='1'}, Student{age=16, name='A16', fraction=92, sex='woman', teaId='1'}]
[Student{age=19, name='A19', fraction=80, sex='man', teaId='3'}, Student{age=15, name='A15', fraction=92, sex='man', teaId='3'}]
2.4.2.3 flatMapToInt
test() {
		List<List<Student>> studentList = new ArrayList<>();
        List<Student> students = getStudents();
        List<Student> students2 = getStudents2();
        studentList.add(students);
        studentList.add(students2);
        // 收集所有学生的成绩
        IntStream intStream =
                studentList.stream()
                        .flatMapToInt(stus ->
                                stus.stream()
                                        .mapToInt(Student::getFraction));
		// 遍历输出,并计算平均估值
         OptionalDouble average = intStream.peek(System.out::println).average();
         System.out.println("average: " + average.getAsDouble());
 }

输出

...
60
50
50
80
average: 67.63636363636364

2.5 归约(reduce)

归约,也称缩减,顾名思义,是把一个流缩减成一个值,能实现对集合求和、求乘积和求最值操作。

2.5.1 简单案例
test() {
        List<Integer> list = Arrays.asList(1, 3, 5, 7, 9, 11);
        // 求和方式1
        Optional<Integer> sum = list.stream().reduce((x, y) -> x + y);
        // 求和方式2
        Optional<Integer> sum2 = list.stream().reduce(Integer::sum);
        // 求和方式3
        Integer sum3 = list.stream().reduce(0, Integer::sum);

        // 求乘积
        Optional<Integer> product = list.stream().reduce((x, y) -> x * y);

        // 求最大值方式1
        Optional<Integer> max = list.stream().reduce((x, y) -> x > y ? x : y);
        // 求最大值写法2
        Integer max2 = list.stream().reduce(1, Integer::max);

        System.out.println("list求和:" + sum.get() + "," + sum2.get() + "," + sum3);
        System.out.println("list求积:" + product.get());
        System.out.println("list求和:" + max.get() + "," + max2);
 }

输出

list求和:36,36,36
list求积:10395
list求和:11,11
2.5.2 对象案例
test() {
		List<Student> students = getStudents();
        // 求所有学生成绩和
        // 方式1
        Optional<Integer> sum1 = students.stream().map(Student::getFraction).reduce(Integer::sum);
        // 方式2
        Optional<Integer> sum2 = students.stream().map(Student::getFraction).reduce((sum, item) -> sum += item);
        // 其他方式
        Integer sum = students.stream().mapToInt(Student::getFraction).sum();
        System.out.println("求和:" + sum1.get() + "," + sum2.get() + "," + sum);

        // 求学生中最高成绩
        Optional<Integer> max1 = students.stream().map(Student::getFraction).reduce(Integer::max);
        // 其他方式
        OptionalInt max2 = students.stream().mapToInt(Student::getFraction).max();
        System.out.println("最大值:" + max1.get() + "," + max2.getAsInt());
  }

输出

求和:504,504,504
最大值:92,92

2.6 收集(collect)

收集(collect),可以说是内容最繁多、功能最丰富的部分、在开发过程中最常用的。从字面上去理解,就是把一个流收集起来,最终将流转换成新的集合List<?>、Map<?, ?>、Set<?>。

2.6.1 归集(toList/toSet/toMap)
test() {
 		List<Student> students = getStudents();
        // 获取所有学生的名字,存储到List<String>集合中
        List<String> nameList = students.stream().map(Student::getName).collect(Collectors.toList());
        // 流转换->Map<key, Student> key:学生姓名
        Map<String, Student> mapStudent = students.stream().collect(Collectors.toMap(Student::getName, Function.identity()));
        // 流转换->Set<Student>
        Set<Student> setStudent = students.stream().collect(Collectors.toSet());
        System.out.println("toList: " + nameList);
        System.out.println("toMap: " + mapStudent);
        System.out.println("toSet: " + setStudent);
  }

输出

toList: [A18, A17, A19, A20, A25, A15, A16]
toMap: {A25=Student{age=25, name='A25', fraction=40, sex='man', teaId='1'}, A15=Student{age=15, name='A15', fraction=92, sex='man', teaId='3'}, A16=Student{age=16, name='A16', fraction=92, sex='woman', teaId='1'}, A17=Student{age=17, name='A17', fraction=50, sex='woman', teaId='1'}, A18=Student{age=18, name='A18', fraction=60, sex='man', teaId='1'}, A19=Student{age=19, name='A19', fraction=80, sex='man', teaId='3'}, A20=Student{age=20, name='A20', fraction=90, sex='woman', teaId='2'}}
toSet: [Student{age=18, name='A18', fraction=60, sex='man', teaId='1'}, Student{age=25, name='A25', fraction=40, sex='man', teaId='1'}, Student{age=19, name='A19', fraction=80, sex='man', teaId='3'}, Student{age=17, name='A17', fraction=50, sex='woman', teaId='1'}, Student{age=16, name='A16', fraction=92, sex='woman', teaId='1'}, Student{age=20, name='A20', fraction=90, sex='woman', teaId='2'}, Student{age=15, name='A15', fraction=92, sex='man', teaId='3'}]
2.6.1 统计(count/averaging)

提供了一系列用于数据统计的静态方法:

  1. 计数:count
  2. 平均值:averagingInt、averagingLong、averagingDouble
  3. 最值:maxBy、minBy
  4. 求和:summingInt、summingLong、summingDouble
    统计以上所有:summarizingInt、summarizingLong、summarizingDouble
test() {
        List<Student> students = getStudents();
        // 求总数
        Long count = students.stream().collect(Collectors.counting());
        // 求平均成绩
        Double avg = students.stream().collect(Collectors.averagingDouble(Student::getFraction));
        // 求最高成绩
        Optional<Integer> max = students.stream().map(Student::getFraction).collect(Collectors.maxBy(Integer::compareTo));
        // 求最低成绩
        Optional<Integer> min = students.stream().map(Student::getFraction).collect(Collectors.minBy(Integer::compareTo));
        // 成绩求和
        Double sum = students.stream().collect(Collectors.summingDouble(s -> s.getFraction()));
        // 一次性统计
        DoubleSummaryStatistics collect = students.stream().collect(Collectors.summarizingDouble(s -> s.getFraction()));

        System.out.println("总数: " + count);
        System.out.println("平均成绩: " + avg);
        System.out.println("最高成绩: " + max);
        System.out.println("最低成绩: " + min);
        System.out.println("成绩求和: " + sum);
        System.out.println("学生成绩一次性统计: " + collect);
}

输出

总数: 7
平均成绩: 72.0
最高成绩: Optional[92]
最低成绩: Optional[40]
成绩求和: 504.0
学生成绩一次性统计: DoubleSummaryStatistics{count=7, sum=504.000000, min=40.000000, average=72.000000, max=92.000000}
2.6.3 分组 (partitioningBy/groupingBy)

分区:将stream按条件分为两个Map<Boolean, Object>,比如学生按成绩是否高于80分为两部分。
分组:将集合分为多个Map,比如学生按性别分组;有单级分组和多级分组。

test() {
        List<Student> students = getStudents();
        // 分组:按性别分组
        Map<String, List<Student>> sexStudents = students.stream().collect(Collectors.groupingBy(Student::getSex));
        // 分区:按成绩[0, 80), [80,100]分区
        Map<Boolean, List<Student>> collect = students.stream().collect(Collectors.partitioningBy(stu -> stu.getFraction() >= 80));
        // 二级分组:先按性别分组,在按成绩分区
        Map<String, Map<Boolean, List<Student>>> collect1 = students.stream().collect(Collectors.groupingBy(Student::getSex, Collectors.partitioningBy(stu -> stu.getFraction() >= 80)));
        System.out.println("按性别分组:" + sexStudents);
        System.out.println("按成绩分区:" + collect);
        System.out.println("按性别分组,再按成绩分区:" + collect1);
}

输出

按性别分组:{woman=[Student{age=17, name='A17', fraction=50, sex='woman', teaId='1'}, Student{age=20, name='A20', fraction=90, sex='woman', teaId='2'}, Student{age=16, name='A16', fraction=92, sex='woman', teaId='1'}], man=[Student{age=18, name='A18', fraction=60, sex='man', teaId='1'}, Student{age=19, name='A19', fraction=80, sex='man', teaId='3'}, Student{age=25, name='A25', fraction=40, sex='man', teaId='1'}, Student{age=15, name='A15', fraction=92, sex='man', teaId='3'}]}
按成绩分区:{false=[Student{age=18, name='A18', fraction=60, sex='man', teaId='1'}, Student{age=17, name='A17', fraction=50, sex='woman', teaId='1'}, Student{age=25, name='A25', fraction=40, sex='man', teaId='1'}], true=[Student{age=19, name='A19', fraction=80, sex='man', teaId='3'}, Student{age=20, name='A20', fraction=90, sex='woman', teaId='2'}, Student{age=15, name='A15', fraction=92, sex='man', teaId='3'}, Student{age=16, name='A16', fraction=92, sex='woman', teaId='1'}]}
按性别分组,再按成绩分区:{woman={false=[Student{age=17, name='A17', fraction=50, sex='woman', teaId='1'}], true=[Student{age=20, name='A20', fraction=90, sex='woman', teaId='2'}, Student{age=16, name='A16', fraction=92, sex='woman', teaId='1'}]}, man={false=[Student{age=18, name='A18', fraction=60, sex='man', teaId='1'}, Student{age=25, name='A25', fraction=40, sex='man', teaId='1'}], true=[Student{age=19, name='A19', fraction=80, sex='man', teaId='3'}, Student{age=15, name='A15', fraction=92, sex='man', teaId='3'}]}}

2.6.4 接合 (joining)

joining可以将stream中的元素用特定的连接符,没有的话,则直接连接成一个字符串。

test() {
        List<Student> students = getStudents();
        String collect = students.stream().map(stu -> stu.getName()).collect(Collectors.joining());
        String collect1 = students.stream().map(stu -> stu.getName()).collect(Collectors.joining(","));
        System.out.println(collect);
        System.out.println("学生姓名:" + collect1);
}        

输出

A18A17A19A20A25A15A16
学生姓名:A18,A17,A19,A20,A25,A15,A16

2.7 排序(sorted)

sorted,中间操作。有两种排序:

  1. sorted():自然排序,流中元素需实现Comparable接口
  2. sorted(Comparator com):Comparator排序器自定义排序
2.7.1 自然排序
test() {
        List<Student> students = getStudents();
        // 按成绩从小到大排序
        String collect = students.stream().sorted(Comparator.comparing(Student::getFraction)).map(stu -> String.valueOf(stu.getFraction())).collect(Collectors.joining(","));
        // 按成绩成大到小排序
        String collect1 = students.stream().sorted(Comparator.comparing(Student::getFraction).reversed()).map(stu -> String.valueOf(stu.getFraction())).collect(Collectors.joining(","));

        System.out.println("按成绩从小到大:" + collect);
        System.out.println("按成绩从大到小:" + collect1);
 }

输出

按成绩从小到大:40,50,60,80,90,92,92
按成绩从大到小:92,92,90,80,60,50,40
2.7.2 自定义排序
test() {
        List<Student> students = getStudents();
        // 先按年龄从小到大排序,再按成绩从大到小排序
        List<String> collect = students.stream().sorted(Comparator.comparing(Student::getAge).thenComparing(Comparator.comparing(Student::getFraction).reversed()))
                .map(stu -> "年龄:" + stu.getAge() + " 成绩:" + stu.getFraction()).collect(Collectors.toList());
        // 自定义
        List<String> collect1 = students.stream().sorted((s1, s2) -> {
            if (s1.getAge() == s2.getAge()) {
                // 成绩降序
                return s2.getFraction() - s1.getFraction();
            } else {
                // 年龄升序
                return s1.getAge() - s2.getAge();
            }
        }).map(stu -> "年龄:" + stu.getAge() + " 成绩:" + stu.getFraction()).collect(Collectors.toList());
        System.out.println(collect);
        System.out.println(collect1);
 }

输出

[年龄:15 成绩:92, 年龄:16 成绩:92, 年龄:17 成绩:50, 年龄:18 成绩:60, 年龄:19 成绩:80, 年龄:20 成绩:90, 年龄:25 成绩:40]
[年龄:15 成绩:92, 年龄:16 成绩:92, 年龄:17 成绩:50, 年龄:18 成绩:60, 年龄:19 成绩:80, 年龄:20 成绩:90, 年龄:25 成绩:40]

2.8 提取/合并

流也可以进行合并、去重、限制、跳过等操作。

  1. concat:合并留。
  2. distinct:去重,去重的判断方法是对象自带equal。
  3. limit:限制从流中获得前n个数据。
  4. skip:跳过。
2.8.1 合并 concat
test() {
        String[] arr1 = { "1", "2", "3", "4" };
        String[] arr2 = { "4", "5", "6", "7" };
        Stream<String> stream1 = Stream.of(arr1);
        Stream<String> stream2 = Stream.of(arr2);
        // concat 合并
        List<String> collect = Stream.concat(stream1, stream2).collect(Collectors.toList());
        System.out.println("合并:" + collect);
}

输出

合并:[1, 2, 3, 4, 4, 5, 6, 7]
2.8.2 去重 distinct
test() {
  		String[] arr1 = { "1", "2", "3", "4" };
        String[] arr2 = { "4", "5", "6", "7" };
        Stream<String> stream1 = Stream.of(arr1);
        Stream<String> stream2 = Stream.of(arr2);
        // distinct去重
        List<String> collect1 = Stream.concat(stream1, stream2).distinct().collect(Collectors.toList());
        System.out.println("去重:" + collect1);
}

输出

去重:[1, 2, 3, 4, 5, 6, 7]
2.8.3 限制 limit
test() {
 		String[] arr1 = { "1", "2", "3", "4" };
        String[] arr2 = { "4", "5", "6", "7" };
        Stream<String> stream1 = Stream.of(arr1);
        Stream<String> stream2 = Stream.of(arr2);
        // limit限制 取前3位
        List<String> collect2 = Stream.concat(stream1, stream2).limit(3).collect(Collectors.toList());
        System.out.println("限制:" + collect2);
}

输出

限制:[1, 2, 3]
2.8.4 跳过 skip
test() {
 		String[] arr1 = { "1", "2", "3", "4" };
        String[] arr2 = { "4", "5", "6", "7" };
        Stream<String> stream1 = Stream.of(arr1);
        Stream<String> stream2 = Stream.of(arr2);
        // skip:跳过 前4位
        List<String> collect3 = Stream.concat(stream1, stream2).skip(4);
 }

输出

跳过:[4, 5, 6, 7]

2.9 总结

  1. 程序运行中,流Stream只能使用一次,使用后会默认关闭,不能重复使用;重复使用会报错,信息如下:
Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
	at java.util.stream.AbstractPipeline.spliterator(AbstractPipeline.java:343)
	at java.util.stream.Stream.concat(Stream.java:1080)
  1. 在开发过程中,建议使用Stream.of(list),解决list为null的问题;使用list.stream()之前需要判断list是否为null,避免报错空指针异常(java.lang.NullPointerException)。
  2. 动起手来敲代码验证,会有不一样的收获。
  3. stream流遍历获取的对象是原对象
  4. stream特性思维导图:
    在这里插入图片描述
  • 7
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值