9张图,32个案例带你轻松玩转Java stream(上)

简介: 9张图,32个案例带你轻松玩转Java stream

大家好,我是君哥。

Java8 中增加了 Stream 处理,可以配合 Lambda 表达式来使用,让操作集合非常便利。虽然我们平时经常使用 Stream,但用到的方法其实非常少,这篇文章就来完整的介绍 Stream 的使用。

微信图片_20221213105106.png

Stream 提供的方法非常多,按照调用当前方法是否结束流处理,可以分为中间操作和结束操作。

对于中间操作,又可以分为有状态的操作和无状态操作:

  • 无状态的操作是指当前元素的操作不受前面元素的影响。
  • 有状态的操作是指当前元素的操作需要等所有元素处理完之后才能进行。

对于结束操作,又可以分为短路操作和非短路操作,具体如下:

  • 短路操作是指不需要处理完全部的元素就可以结束。
  • 非短路操作是指必须处理完所有元素才能结束。

1 创建 Stream

1.1 使用集合创建

List<Integer> list = Arrays.asList(5, 2, 3, 1, 4);
Stream stream = list.stream();

1.2 使用数组创建

String[] array={"ab", "abc", "abcd", "abcde", "abcdef" };
Stream<String> stream = Arrays.stream(array);

1.3 使用 Stream 静态方法

Stream<String> stream = Stream.of("ab", "abc", "abcd", "abcde", "abcdef");
Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 3).limit(5);
stream2.forEach(r -> System.out.print(r + " "));
System.out.println();
Stream<Integer> stream3 = Stream.generate(new Random()::nextInt).limit(3);
stream3.forEach(r -> System.out.print(r + " "));

上面代码输出如下:

0 3 6 9 12

-150231306 -1769565695 102740625

2 无状态操作


微信图片_20221213105136.png

2.1 map

接收一个函数作为入参,把这个函数应用到每个元素上,执行结果组成一个新的 stream 返回。

微信图片_20221213105157.png

案例 1:对整数数组每个元素加 3 :

List<Integer> list = Arrays.asList(5, 2, 3, 1, 4);
List<Integer> newList = list.stream().map(x -> x + 3).collect(Collectors.toList());
System.out.println("newList:" + newList);

上面代码输出结果如下:

newList:[8, 5, 6, 4, 7]

案例 2:把字符串数组的每个元素转换为大写:

List<String> list = Arrays.asList("ab", "abc", "abcd", "abcde", "abcdef");
List<String> newList = list.stream().map(String::toUpperCase).collect(Collectors.toList());
System.out.println("newList:" + newList);

上面代码输出结果如下:

newList:[AB, ABC, ABCD, ABCDE, ABCDEF]

2.2 mapToXXX

包括三个方法:mapToInt、mapToDouble、mapToLong

案例 3:把字符串数组转为整数数组:

List<String> list = Arrays.asList("ab", "abc", "abcd", "abcde", "abcdef");
int[] newList = list.stream().mapToInt(r -> r.length()).toArray();
System.out.println("newList:" + Arrays.toString(newList));

上面代码输出结果如下:

newList:[2, 3, 4, 5, 6]

2.3 flatMap

flatMap接收函数作为入参,然后把集合中每个元素转换成一个 stream,再把这些 stream 组成一个新的 stream,是拆分单词很好的工具。如下图:

微信图片_20221213105222.png

案例 4:把一个字符串数组转成另一个字符串数组:

List<String> list = Arrays.asList("ab-abc-abcd-abcde-abcdef", "5-2-3-1-4");
List<String> newList = list.stream().flatMap(s -> Arrays.stream(s.split("-"))).collect(Collectors.toList());
System.out.println("newList:" + newList);

上面代码输出结果:

newList:[ab, abc, abcd, abcde, abcdef, 5, 2, 3, 1, 4]

2.4 flatMapToXXX

类似于 flatMap,返回一个 XXXStream。

包括三个方法:flatMapToInt、flatMapToLong、flatMapToDouble

案例 5:对给定的二维整数数组求和:

int[][] data = {{1,2},{3,4},{5,6}};
IntStream intStream = Arrays.stream(data).flatMapToInt(row -> Arrays.stream(row));
System.out.println(intStream.sum());

输出结果为:21。

2.5 filter

筛选功能,按照一定的规则将符合条件的元素提取到新的流中。

定义一个学生类,包含姓名、年龄、性别、考试成绩四个属性:

class Student{
    private String name;
    private Integer age;
    private String sex;
    private Integer score;
    public Student(String name, Integer age, String sex, Integer score){
        this.name = name;
        this.age = age;
        this.score = score;
        this.sex = sex;
    }
    //省略getters/setters
}

案例 6:找出考试成绩在 90 分以上的学生姓名:

List<Student> students = new ArrayList<>();
students.add(new Student("Mike", 10, "male", 88));
students.add(new Student("Jack", 13,"male", 90));
students.add(new Student("Lucy", 15,"female", 100));
students.add(new Student("Jessie", 12,"female", 78));
students.add(new Student("Allon", 16,"female", 92));
students.add(new Student("Alis", 22,"female", 50));
List<String> nameList = students.stream().filter(x -> x.getScore() >= 90).map(Student::getName).collect(Collectors.toList());
System.out.print("考试成绩90分以上的学生姓名:" + nameList);

输出如下:

考试成绩90分以上的学生姓名:[Jack, Lucy, Allon]

2.6 peek

返回由 stream 中元素组成的新 stream,用给定的函数作用在新 stream 的每个元素上。传入的函数是一个 Consume 类型的,没有返回值,因此并不会改变原 stream 中元素的值。peek 主要用是 debug,可以方便地 查看流处理结果是否正确。

案例 7:过滤出 stream 中长度大于 3 的字符串并转为大写:

Stream.of("one", "two", "three", "four")
             .filter(e -> e.length() > 3)
             .peek(e -> System.out.println("Filtered value: " + e))
             .map(String::toUpperCase)
             .peek(e -> System.out.println("Mapped value: " + e))
             .collect(Collectors.toList());

输出结果如下:

Filtered value: three

Mapped value: THREE

Filtered value: four

Mapped value: FOUR

2.7 unordered

把一个有序的 stream 转成一个无序 stream ,如果原 stream 本身就是无序的,可能会返回原始的 stream。

案例 8:把一个有序数组转成无序

Arrays.asList("1", "2", "3", "4", "5")
                .parallelStream()
                .unordered()
                .forEach(r -> System.out.print(r + " "));

每次执行输出的结果不一样,下面是一次输出的结果:

3 5 4 2 1

3 有状态操作

微信图片_20221213105304.png

3.1 distinct

去重功能。

案例 9 :去掉字符串数组中的重复字符串

String[] array = { "a", "b", "b", "c", "c", "d", "d", "e", "e"};
List<String> newList = Arrays.stream(array).distinct().collect(Collectors.toList());
System.out.println("newList:" + newList);

输出结果:

newList:[a, b, c, d, e]

3.2 limit

限制从 stream 中获取前 n 个元素。

案例 10 :从数组中获取前 5 个元素

String[] array = { "c", "c", "a", "b", "b", "e", "e", "d", "d"};
List<String> newList = Arrays.stream(array).limit(5).collect(Collectors.toList());
System.out.println("newList:" + newList);

输出结果:

newList:[c, c, a, b, b]

3.3 skip

跳过 Stream 中前 n 个元素

案例 11:从数组中获取第 5 个元素之后的元素

String[] array = { "a", "b", "c", "d", "e", "f", "g", "h", "i"};
List<String> newList = Arrays.stream(array).skip(5).collect(Collectors.toList());
System.out.println("newList:" + newList);

输出结果:

newList:[f, g, h, i]

3.4 sorted

排序功能。

案例 12:对给定数组进行排序

String[] array = { "c", "c", "a", "b", "b", "e", "e", "d", "d"};
List<String> newList = Arrays.stream(array).sorted().collect(Collectors.toList());
System.out.println("newList:" + newList);

输出结果:

newList:[a, b, b, c, c, d, d, e, e]

案例 13:按照学生成绩进行排序

List<Student> students = new ArrayList<>();
students.add(new Student("Mike", 10, "male", 88));
students.add(new Student("Jack", 13,"male", 90));
students.add(new Student("Lucy", 15,"female", 100));
students.add(new Student("Jessie", 12,"female", 78));
students.add(new Student("Allon", 16,"female", 92));
students.add(new Student("Alis", 22,"female", 50));
List<String> nameList = students.stream().sorted(Comparator.comparing(Student::getScore)).map(Student::getName).collect(Collectors.toList());
System.out.print("按成绩排序输出学生姓名:" + nameList);

输出结果:

考试成绩90分以上的学生姓名:[Alis, Jessie, Mike, Jack, Allon, Lucy]

相关文章
|
19天前
|
jenkins Java 测试技术
如何使用 Jenkins 自动发布 Java 代码,通过一个电商公司后端服务的实际案例详细说明
本文介绍了如何使用 Jenkins 自动发布 Java 代码,通过一个电商公司后端服务的实际案例,详细说明了从 Jenkins 安装配置到自动构建、测试和部署的全流程。文中还提供了一个 Jenkinsfile 示例,并分享了实践经验,强调了版本控制、自动化测试等关键点的重要性。
53 3
|
20天前
|
存储 Java 关系型数据库
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践,包括连接创建、分配、复用和释放等操作,并通过电商应用实例展示了如何选择合适的连接池库(如HikariCP)和配置参数,实现高效、稳定的数据库连接管理。
39 2
|
22天前
|
Java 关系型数据库 数据库
面向对象设计原则在Java中的实现与案例分析
【10月更文挑战第25天】本文通过Java语言的具体实现和案例分析,详细介绍了面向对象设计的五大核心原则:单一职责原则、开闭原则、里氏替换原则、接口隔离原则和依赖倒置原则。这些原则帮助开发者构建更加灵活、可维护和可扩展的系统,不仅适用于Java,也适用于其他面向对象编程语言。
14 2
|
23天前
|
Java API 数据处理
探索Java中的Lambda表达式与Stream API
【10月更文挑战第22天】 在Java编程中,Lambda表达式和Stream API是两个强大的功能,它们极大地简化了代码的编写和提高了开发效率。本文将深入探讨这两个概念的基本用法、优势以及在实际项目中的应用案例,帮助读者更好地理解和运用这些现代Java特性。
|
27天前
|
安全 Java
Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧
【10月更文挑战第20天】Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧,包括避免在循环外调用wait()、优先使用notifyAll()、确保线程安全及处理InterruptedException等,帮助读者更好地掌握这些方法的应用。
17 1
|
1月前
|
Java 数据库
案例一:去掉数据库某列中的所有英文,利用java正则表达式去做,核心:去掉字符串中的英文
这篇文章介绍了如何使用Java正则表达式从数据库某列中去除所有英文字符。
46 15
|
1月前
|
jenkins Java 测试技术
如何使用 Jenkins 自动发布 Java 代码,通过一个电商公司后端服务的实际案例详细说明
【10月更文挑战第8天】本文介绍了如何使用 Jenkins 自动发布 Java 代码,通过一个电商公司后端服务的实际案例,详细说明了从 Jenkins 安装配置到自动构建、测试和部署的全流程。文中还提供了一个 Jenkinsfile 示例,并分享了实践经验,强调了版本控制、自动化测试等关键点的重要性。
36 5
|
1月前
|
分布式计算 NoSQL Java
Hadoop-32 ZooKeeper 分布式锁问题 分布式锁Java实现 附带案例和实现思路代码
Hadoop-32 ZooKeeper 分布式锁问题 分布式锁Java实现 附带案例和实现思路代码
43 2
|
1月前
|
Java API 数据处理
java Stream详解
【10月更文挑战第4天】
26 0
|
1月前
|
Java C#
Java的监听处理事件--小球移动案例
Java的监听处理事件--小球移动案例
13 0
下一篇
无影云桌面