龙空技术网

玩转 Java8 Stream,让你代码更高效紧凑简洁

Java大蜗牛 3519

前言:

此刻朋友们对“java 取最大值”都比较关怀,我们都想要了解一些“java 取最大值”的相关文章。那么小编在网络上汇集了一些关于“java 取最大值””的相关文章,希望你们能喜欢,你们一起来学习一下吧!

文章目录前言一、Stream 特性二、Stream 创建2.1 用集合创建流2.2 用数组创建流2.3 Stream静态方法三、Stream 使用案例3.1 遍历 forEach3.2 过滤 filter3.3 查找 findFirst,findAny3.4 匹配 match3.5 映射 map3.6 截取流 limit3.7 排序 sorted3.8 去重 distinct3.9 统计 summaryStatistics3.10 归约 reduce3.11 归集 toList,toSet,toMap3.12 分组 partitioningBy,groupingBy3.13 合并 joining四、演示代码获取前言

Java 8 (又称为 jdk 1.8) 是 Java 语言开发的一个主要版本。 Oracle 公司于 2014 年 3 月 18 日发布 Java 8 ,它支持函数式编程,新的 JavaScript 引擎,新的日期 API,新的Stream API 等。

新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。它可以让你以一种声明的方式处理数据,从而写出高效率、干净、简洁的代码。

这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。

一、Stream 特性元素是特定类型的对象,形成一个队列。 Java中的Stream不会存储元素,而是按需计算按照特定的规则对数据进行计算,一般会输出结果。Stream不会改变数据源,一般情况下会产生一个新的集合或者新值。Stream流的来源,可以是集合,数组,I/O channel, 产生器generator 等等。Stream具有延迟执行特性,只有调用终端操作时,中间操作才会执行。中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。

Stream流的操作可以大概分为2种:

中间操作:每次操作都返回流对象本身。终端操作:一个流只可以进行一次终端操作,即产生一个新的集合或者新值。终端操作结束后流无法再次使用。二、Stream 创建

在 Java 8 中, Stream可以由集合或数组创建而来,生成的流有2种类型:

stream() :串行流,由主线程按顺序对流执行操作。parallelStream() :并行流,内部以多线程并行执行的方式对流进行操作,但前提是流中的数据处理没有顺序要求。例如计算集合中的数量之和。如果流种数据量很大,并行流可以加快处理速度。串行流可以通过parallel()方法把顺序流转换成并行流。

2.1 用集合创建流

因为集合继承或实现了java.util.Collection接口,而Collection接口定义了stream()parallelStream()方法,所以可通过集合的stream() 和parallelStream()方法创建流。

// 创建集合List<String> list = Arrays.asList("张三", "李四", "王五");// 创建一个串行流Stream<String> stream = list.stream();// 创建一个并行流Stream<String> parallelStream = list.parallelStream();123456
2.2 用数组创建流

使用java.util.Arrays.stream(T[] array)方法用数组创建流。

// 创建数组String[] persons = {"张三", "李四", "王五"};// 创建一个串行流Stream<String> stream = Arrays.stream(persons);// 创建一个并行流Stream<String> parallelStream = Arrays.stream(persons).parallel();123456
2.3 Stream静态方法

使用Stream的静态方法生成Stream,例如of()iterate()generate()等。

Stream<String> stream2 = Stream.of("张三", "李四", "王五");// 输出5个奇数 1 3 5 7 9Stream<Integer> stream3 = Stream.iterate(1, x -> x + 2).limit(5);stream3.forEach(System.out::println);// 生成2个UUIDStream<UUID> stream4 = Stream.generate(UUID::randomUUID).limit(2);stream4.forEach(System.out::println);123456789
三、Stream 使用案例

以下所有案例会基于学生数据,学生类,以及测试数据如下:

package com.nobody;/** * @Description 学生类 * @Author Mr.nobody * @Date 2021/1/17 * @Version 1.0 */public class Student {    // 主键    private String id;    // 姓名    private String name;    // 年龄    private int age;    // 性别    private String sex;    // 成绩    private double score;    public Student(String id, String name, int age, String sex, double score) {        this.id = id;        this.name = name;        this.age = age;        this.sex = sex;        this.score = score;    }	// 省略get和set方法,toString方法,如若测试需自行添加12345678910111213141516171819202122232425262728
List<Student> students = new ArrayList<>(16);students.add(new Student("1", "张三", 18, "male", 88));students.add(new Student("2", "李四", 17, "male", 60));students.add(new Student("3", "王五", 18, "male", 100));students.add(new Student("4", "赵六", 20, "male", 10));students.add(new Student("5", "董七", 14, "female", 95));students.add(new Student("6", "幺八", 21, "male", 55));students.add(new Student("7", "老九", 20, "female", 66));students.add(new Student("8", "小明", 18, "male", 100));students.add(new Student("9", "小红", 22, "female", 95));students.add(new Student("10", "小张", 25, "male", 90));1234567891011
3.1 遍历 forEach
students.stream().forEach(System.out::println);// 输出结果Student{id='1', name='张三', age=18, sex=male, score=88.0}Student{id='2', name='李四', age=17, sex=male, score=60.0}Student{id='3', name='王五', age=18, sex=male, score=100.0}Student{id='4', name='赵六', age=20, sex=male, score=10.0}Student{id='5', name='董七', age=14, sex=female, score=95.0}Student{id='6', name='幺八', age=21, sex=male, score=55.0}Student{id='7', name='老九', age=20, sex=female, score=66.0}Student{id='8', name='小明', age=18, sex=male, score=100.0}Student{id='9', name='小红', age=22, sex=female, score=95.0}Student{id='10', name='小张', age=25, sex=male, score=90.0}12345678910111213
3.2 过滤 filter
// 过滤出成绩100分的学生List<Student> students1 =        students.stream().filter(student -> student.getScore() == 100).collect(Collectors.toList());students1.forEach(System.out::println);// 输出结果Student{id='3', name='王五', age=18, sex=male, score=100.0}Student{id='8', name='小明', age=18, sex=male, score=100.0}12345678
3.3 查找 findFirst,findAny

一般filter和find搭配使用,即从过滤符合条件的数据中,获得一个数据。

// 串行流,匹配第一个Optional<Student> studentOptional =        students.stream().filter(student -> student.getAge() >= 20).findFirst();if (studentOptional.isPresent()) {    Student student = studentOptional.get();    System.out.println(student);}// 上面输出语句可简写如下// studentOptional.ifPresent(System.out::println);// 并行流,匹配任意一个,findAny一般用于并行流Optional<Student> studentOptiona2 =        students.parallelStream().filter(student -> student.getAge() >= 20).findAny();studentOptiona2.ifPresent(System.out::println);// 输出结果Student{id='4', name='赵六', age=20, sex=male, score=10.0}Student{id='7', name='老九', age=20, sex=female, score=66.0}123456789101112131415161718
3.4 匹配 match
// 是否存在100分的学生boolean anyMatch = students.stream().anyMatch(student -> student.getScore() == 100);// 是否全部学生都100分boolean allMatch = students.stream().allMatch(student -> student.getScore() == 100);// 是否全部学生都没有100分boolean noneMatch = students.stream().noneMatch(student -> student.getScore() == 100);System.out.println(anyMatch);System.out.println(allMatch);System.out.println(noneMatch);// 输出结果truefalsefalse1234567891011121314
3.5 映射 map

映射,顾名思义,将一个对象映射成另外一个对象。即一个Stream流中的所有元素按照一定的映射规则,映射到另一个流中。映射有map和flatMap两种类型:

map:接收一个函数作为参数,此函数作用到Stream中每一个元素,形成一个新的元素,所有新的元素组成一个新的流。

flatMap:接收一个函数作为参数,它将流中的每个元素都转换成另一个流,然后把所有流再连接形成一个最终流。

// 获取每个学生的姓名List<String> studentNames =        students.stream().map(Student::getName).collect(Collectors.toList());System.out.println(studentNames);// 每个学生的成绩加10分List<Double> studentScores = students.stream().map(student -> student.getScore() + 10)        .collect(Collectors.toList());System.out.println(studentScores);// 输出结果[张三, 李四, 王五, 赵六, 董七, 幺八, 老九, 小明, 小红, 小张][98.0, 70.0, 110.0, 20.0, 105.0, 65.0, 76.0, 110.0, 105.0, 100.0]123456789101112
List<String> list = Arrays.asList("a-b-c-d", "g-h-i");List<String> list1 = list.stream().flatMap(s -> Arrays.stream(s.split("-"))).collect(Collectors.toList());System.out.println(list1);// 输出结果[a, b, c, d, g, h, i]123456
3.6 截取流 limit
// limit方法用于获取指定数量的流。例如下面演示取出学习成绩大于70的5个人List<Student> students2 = students.stream().filter(student -> student.getScore() > 70)        .limit(5).collect(Collectors.toList());students2.forEach(System.out::println);// 跳过第一个再取2个List<Student> students8 = students.stream().skip(1).limit(2).collect(Collectors.toList());// 获取5个int随机数,按从小到大排序Random random = new Random();random.ints().limit(5).sorted().forEach(System.out::println);// 输出结果Student{id='1', name='张三', age=18, sex=male, score=88.0}Student{id='3', name='王五', age=18, sex=male, score=100.0}Student{id='5', name='董七', age=14, sex=female, score=95.0}Student{id='8', name='小明', age=18, sex=male, score=100.0}Student{id='9', name='小红', age=22, sex=female, score=95.0}-14902027141453405473683321553883993981099579920123456789101112131415161718192021
3.7 排序 sorted

sorted 方法用于对流中的元素进行排序,有两种排序:

sorted():自然排序,流中元素需要实现Comparable接口。

sorted(Comparator<? super T> comparator):需要自定义排序器。

// 按成绩升序List<Student> students3 = students.stream().sorted(Comparator.comparing(Student::getScore))        .collect(Collectors.toList());System.out.println("按成绩升序");students3.forEach(System.out::println);// 按成绩降序List<Student> students4 =        students.stream().sorted(Comparator.comparing(Student::getScore).reversed())                .collect(Collectors.toList());System.out.println("按成绩降序");students4.forEach(System.out::println);// 按成绩升序,再按年龄升序List<Student> students5 = students.stream()        .sorted(Comparator.comparing(Student::getScore).thenComparing(Student::getAge))        .collect(Collectors.toList());System.out.println("按成绩升序,再按年龄升序");students5.forEach(System.out::println);// 按成绩升序,再按年龄降序List<Student> students6 = students.stream().sorted((s1, s2) -> {    if (s1.getScore() != s2.getScore()) {        return (int) (s1.getScore() - s2.getScore());    } else {        return (s2.getAge() - s1.getAge());    }}).collect(Collectors.toList());System.out.println("按成绩升序,再按年龄降序");students6.forEach(System.out::println);123456789101112131415161718192021222324252627
3.8 去重 distinct
List<String> list2 = Arrays.asList("a", "b", "a", "c", "f", "e", "f");List<String> list3 = list2.stream().distinct().collect(Collectors.toList());Set<String> stringSet = list2.stream().collect(Collectors.toSet()); // list转set也可以达到去重效果System.out.println(list3);System.out.println(stringSet);// 输出结果[a, b, c, f, e][a, b, c, e, f]123456789
3.9 统计 summaryStatistics

一些收集器能产生统计结果,例如Collectors提供了一系列用于数据统计的静态方法,它们主要用于int、double、long等基本类型上。

// 总和统计summaryStatisticsDoubleSummaryStatistics doubleSummaryStatistics =        students.stream().mapToDouble(Student::getScore).summaryStatistics();System.out.println("平均值:" + doubleSummaryStatistics.getAverage());System.out.println("总个数:" + doubleSummaryStatistics.getCount());System.out.println("最大值:" + doubleSummaryStatistics.getMax());System.out.println("最小值:" + doubleSummaryStatistics.getMin());System.out.println("总和值:" + doubleSummaryStatistics.getSum());// 输出结果平均值:75.9总个数:10最大值:100.0最小值:10.0总和值:759.0123456789101112131415
// 统计个数long count = students.stream().count();// 平均值Double averageScore =        students.stream().collect(Collectors.averagingDouble(Student::getScore));// 最大值和最小值Optional<Double> maxScore = students.stream().map(Student::getScore).max(Double::compare);Optional<Double> minScore = students.stream().map(Student::getScore).min(Double::compare);// 求和double sumScore = students.stream().mapToDouble(Student::getScore).sum();// 一次性统计所有DoubleSummaryStatistics doubleSummaryStatistics1 =        students.stream().collect(Collectors.summarizingDouble(Student::getScore));System.out.println("单个维度计算:");System.out.println("统计个数:" + count);System.out.println("平均值:" + averageScore);maxScore.ifPresent(aDouble -> System.out.println("最大值:" + aDouble));minScore.ifPresent(aDouble -> System.out.println("最小值:" + aDouble));System.out.println("求和:" + sumScore);System.out.println("一次性统计所有:" + doubleSummaryStatistics1);// 输出结果单个维度计算:统计个数:10平均值:75.9最大值:100.0最小值:10.0求和:759.012345678910111213141516171819202122232425262728
3.10 归约 reduce

归约,把一个流归约(缩减)成一个值,能实现对集合求和、求乘积和求最值等操作。

List<Integer> integerList = Arrays.asList(6, 7, 1, 10, 11, 7, 13, 20);// 求和Optional<Integer> sum1 = integerList.stream().reduce(Integer::sum);// 求和,基于10的基础上Integer sum2 = integerList.stream().reduce(10, Integer::sum);// 求最大值Optional<Integer> max1 = integerList.stream().reduce((x, y) -> x > y ? x : y);// 求最大值,基于与50比较的基础上Integer max2 = integerList.stream().reduce(50, Integer::max);Optional<Integer> min = integerList.stream().reduce(Integer::min);// 求乘积Optional<Integer> product = integerList.stream().reduce((x, y) -> x * y);System.out.println("原始集合:" + integerList);System.out.println("集合求和:" + sum1.get() + "," + sum2);System.out.println("集合求最大值:" + max1.get() + "," + max2);System.out.println("集合求最小值:" + min.get());System.out.println("集合求积:" + product.get());// 输出结果原始集合:[6, 7, 1, 10, 11, 7, 13, 20]集合求和:75,85集合求最大值:20,50集合求最小值:1集合求积:8408400123456789101112131415161718192021222324
3.11 归集 toList,toSet,toMap

Java中的Stream不会存储元素,而是按需计算按照特定的规则对数据进行计算,一般会输出结果。所以流中的数据完成处理后,需要将流中的数据重新归集到新的集合里。比较常用的是toList、toSet和toMap,以及复杂的toCollection、toConcurrentMap等。

// 获取学生名字,形成新的list集合List<String> studentNames1 =        students.stream().map(Student::getName).collect(Collectors.toList());// 获取年龄大于等于15的年龄set集合Set<Integer> ageSet = students.stream().filter(student -> student.getAge() >= 15)        .map(Student::getAge).collect(Collectors.toSet());// 创建学生ID和学生实体的mapMap<String, Student> studentMap =        students.stream().collect(Collectors.toMap(Student::getId, student -> student));System.out.println(studentNames1);System.out.println(ageSet);studentMap.forEach((key, value) -> System.out.println(key + ":" + value));// 输出结果[张三, 李四, 王五, 赵六, 董七, 幺八, 老九, 小明, 小红, 小张][17, 18, 20, 21, 22, 25]1:Student{id='1', name='张三', age=18, sex=male, score=88.0}2:Student{id='2', name='李四', age=17, sex=male, score=60.0}3:Student{id='3', name='王五', age=18, sex=male, score=100.0}4:Student{id='4', name='赵六', age=20, sex=male, score=10.0}5:Student{id='5', name='董七', age=14, sex=female, score=95.0}6:Student{id='6', name='幺八', age=21, sex=male, score=55.0}7:Student{id='7', name='老九', age=20, sex=female, score=66.0}8:Student{id='8', name='小明', age=18, sex=male, score=100.0}9:Student{id='9', name='小红', age=22, sex=female, score=95.0}10:Student{id='10', name='小张', age=25, sex=male, score=90.0}1234567891011121314151617181920212223242526
3.12 分组 partitioningBy,groupingBy

partitioningBy(分区):stream中的元素按条件被分为两个Map。

groupingBy(分组):stream中的元素按条件被分为多个Map。

// 按条件学生成绩是否大于等于60,划分为2个组Map<Boolean, List<Student>> studentScorePart = students.stream()        .collect(Collectors.partitioningBy(student -> student.getScore() >= 60));// 按性别分组Map<String, List<Student>> studentSexMap =        students.stream().collect(Collectors.groupingBy(Student::getSex));// 按年龄分组Map<Integer, List<Student>> studentAgeMap =        students.stream().collect(Collectors.groupingBy(Student::getAge));// 先按性别分组,再按年龄分组Map<String, Map<Integer, List<Student>>> collect = students.stream().collect(        Collectors.groupingBy(Student::getSex, Collectors.groupingBy(Student::getAge)));System.out.println("按条件学生成绩是否大于等于60,划分为2个组:");studentScorePart.forEach((aBoolean, students7) -> {    System.out.println("成绩大于等于60?:" + aBoolean);    students7.forEach(System.out::println);});System.out.println("按性别分组:");studentSexMap.forEach((sex, students7) -> {    System.out.println("性别?:" + sex);    students7.forEach(System.out::println);});System.out.println("按年龄分组:");studentAgeMap.forEach((age, students7) -> {    System.out.println("年龄:" + age);    students7.forEach(System.out::println);});System.out.println("先按性别分组,再按年龄分组:");collect.forEach((sex, integerListMap) -> {    System.out.println("性别:" + sex);    integerListMap.forEach((age, students7) -> {        System.out.println("年龄:" + age);        students7.forEach(System.out::println);    });});//输出结果按条件学生成绩是否大于等于60,划分为2个组:成绩大于等于60?:falseStudent{id='4', name='赵六', age=20, sex=male, score=10.0}Student{id='6', name='幺八', age=21, sex=male, score=55.0}成绩大于等于60?:trueStudent{id='1', name='张三', age=18, sex=male, score=88.0}Student{id='2', name='李四', age=17, sex=male, score=60.0}Student{id='3', name='王五', age=18, sex=male, score=100.0}Student{id='5', name='董七', age=14, sex=female, score=95.0}Student{id='7', name='老九', age=20, sex=female, score=66.0}Student{id='8', name='小明', age=18, sex=male, score=100.0}Student{id='9', name='小红', age=22, sex=female, score=95.0}Student{id='10', name='小张', age=25, sex=male, score=90.0}按性别分组:性别?:femaleStudent{id='5', name='董七', age=14, sex=female, score=95.0}Student{id='7', name='老九', age=20, sex=female, score=66.0}Student{id='9', name='小红', age=22, sex=female, score=95.0}性别?:maleStudent{id='1', name='张三', age=18, sex=male, score=88.0}Student{id='2', name='李四', age=17, sex=male, score=60.0}Student{id='3', name='王五', age=18, sex=male, score=100.0}Student{id='4', name='赵六', age=20, sex=male, score=10.0}Student{id='6', name='幺八', age=21, sex=male, score=55.0}Student{id='8', name='小明', age=18, sex=male, score=100.0}Student{id='10', name='小张', age=25, sex=male, score=90.0}按年龄分组:年龄:17Student{id='2', name='李四', age=17, sex=male, score=60.0}年龄:18Student{id='1', name='张三', age=18, sex=male, score=88.0}Student{id='3', name='王五', age=18, sex=male, score=100.0}Student{id='8', name='小明', age=18, sex=male, score=100.0}年龄:20Student{id='4', name='赵六', age=20, sex=male, score=10.0}Student{id='7', name='老九', age=20, sex=female, score=66.0}年龄:21Student{id='6', name='幺八', age=21, sex=male, score=55.0}年龄:22Student{id='9', name='小红', age=22, sex=female, score=95.0}年龄:25Student{id='10', name='小张', age=25, sex=male, score=90.0}年龄:14Student{id='5', name='董七', age=14, sex=female, score=95.0}先按性别分组,再按年龄分组:性别:female年龄:20Student{id='7', name='老九', age=20, sex=female, score=66.0}年龄:22Student{id='9', name='小红', age=22, sex=female, score=95.0}年龄:14Student{id='5', name='董七', age=14, sex=female, score=95.0}性别:male年龄:17Student{id='2', name='李四', age=17, sex=male, score=60.0}年龄:18Student{id='1', name='张三', age=18, sex=male, score=88.0}Student{id='3', name='王五', age=18, sex=male, score=100.0}Student{id='8', name='小明', age=18, sex=male, score=100.0}年龄:20Student{id='4', name='赵六', age=20, sex=male, score=10.0}年龄:21Student{id='6', name='幺八', age=21, sex=male, score=55.0}年龄:25Student{id='10', name='小张', age=25, sex=male, score=90.0}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
3.13 合并 joining

将stream中的元素用指定的连接符(没有的话,则直接连接)连接成一个字符串。

String joinName = students.stream().map(Student::getName).collect(Collectors.joining(", "));System.out.println(joinName);// 输出结果张三, 李四, 王五, 赵六, 董七, 幺八, 老九, 小明, 小红, 小张12345

原文:

作者: Μr.ηobοdy

欢迎点赞+评论+转发!!

标签: #java 取最大值