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]

相关文章
|
1天前
|
安全 Java API
Java Stream API详解与使用
Java Stream API是Java 8引入的特性,提供函数式操作处理集合,支持链式操作和并行处理,提升代码可读性和性能。关键点包括:延迟执行的中间操作(如filter, map)和触发计算的终端操作(如collect, forEach)。示例展示了如何从Person列表过滤出年龄大于20的姓名并排序。使用Stream时注意避免中间操作的副作用,终端操作后Stream不能复用,以及并行操作的线程安全性。
|
1天前
|
Java API 数据处理
Java一分钟之-Stream API:数据处理新方式
【5月更文挑战第13天】Java 8的Stream API为集合操作提供了声明式编程,简化数据处理。本文介绍了Stream的基本概念、常见问题和易错点。问题包括并行流与顺序流的区别,状态改变操作的影响,以及忘记调用终止操作和误用`peek()`。理解并合理使用Stream API能提升代码效率和可维护性。实践中不断探索,将发掘更多Stream API的潜力。
12 3
|
1天前
|
Java 程序员 API
Java 8新特性之Lambda表达式与Stream API的深度解析
【5月更文挑战第12天】本文将深入探讨Java 8中的两个重要新特性:Lambda表达式和Stream API。我们将从基本概念入手,逐步深入到实际应用场景,帮助读者更好地理解和掌握这两个新特性,提高Java编程效率。
41 2
|
1天前
|
Java API
【JAVA进阶篇教学】第三篇:JDK8中Stream API使用
【JAVA进阶篇教学】第三篇:JDK8中Stream API使用
|
1天前
|
设计模式 消息中间件 安全
【Java多线程】关于多线程的一些案例 —— 单例模式中的饿汉模式和懒汉模式以及阻塞队列
【Java多线程】关于多线程的一些案例 —— 单例模式中的饿汉模式和懒汉模式以及阻塞队列
11 0
|
1天前
|
分布式计算 Java API
Java 8新特性之Lambda表达式与Stream API
【5月更文挑战第1天】本文将介绍Java 8中的两个重要特性:Lambda表达式和Stream API。Lambda表达式是一种新的函数式编程语法,可以简化代码并提高可读性。Stream API是一种用于处理集合的新工具,可以方便地进行数据操作和转换。通过结合Lambda表达式和Stream API,我们可以更加简洁高效地编写Java代码。
|
1天前
|
Java 关系型数据库 测试技术
Java代码一键生成数据库文档(案例详解)
Screw是一个自动化数据库文档生成工具,能根据数据库表结构快速生成简洁、多格式(HTML、Word、Markdown)的文档,支持MySQL、MariaDB等多数据库。它使用Freemarker模板,允许用户自定义样式。依赖包括HikariCP数据库连接池和对应JDBC驱动。通过在Java代码或Maven插件中配置,可方便生成文档。示例代码展示了如何在测试用例中使用Screw。文档效果依赖于数据库中的表和字段注释。
|
1天前
|
Java
Java8 Stream Collectors groupingBy使用
Java8 Stream Collectors groupingBy使用
|
1天前
|
Java
【专栏】Java 8 的 Streams 提供了一种处理数据集合的新方式,增强了代码的可读性和可维护性
【4月更文挑战第28天】Java 8 的 Streams 提供了一种处理数据集合的新方式,增强了代码的可读性和可维护性。本文介绍了 Streams 的基本概念,如从数据源创建 Stream,以及中间和终端操作。通过过滤、映射、归并、排序、分组等案例,展示了 Streams 的使用,包括并行 Streams 提高效率。学习 Streams 可以提升代码质量和效率,文章鼓励读者在实际开发中探索更多 Streams 功能。
|
1天前
|
Java API 开发者
【专栏】Java 8的Stream API是处理集合数据的新方式,强调简洁和声明式编程
【4月更文挑战第27天】Java 8的Stream API是处理集合数据的新方式,强调简洁和声明式编程。它基于延迟执行和惰性求值,提供创建、中间操作(如filter、map)和终端操作(如forEach、collect)。示例展示了如何通过Stream排序、过滤、映射和聚合数据。