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]

相关文章
|
3天前
|
Java API 开发者
|
11天前
|
前端开发 Java 测试技术
综合案例【商品管理系统-Java基础版】(附完整源码)
综合案例【商品管理系统-Java基础版】(附完整源码)
47 9
|
11天前
|
存储 算法 Oracle
19 Java8概述(Java8概述+lambda表达式+函数式接口+方法引用+Stream+新时间API)
19 Java8概述(Java8概述+lambda表达式+函数式接口+方法引用+Stream+新时间API)
39 8
|
9天前
|
自然语言处理 Java API
"告别Java8 Stream噩梦,JDFrame神器来袭!让你的代码简洁如诗,效率翻倍,编程新体验等你尝鲜!"
【8月更文挑战第11天】Java 8的Stream API以强大的函数式编程能力革新了集合数据处理方式,但其抽象概念和复杂的链式调用让不少开发者望而却步。为此,JDFrame框架应运而生,通过直观易懂的操作符简化Stream使用,减少代码量并提高效率。
25 3
|
11天前
|
Java
Java数组的2个小案例(杨辉三角分析和商品管理增删改查)
Java数组的2个小案例(杨辉三角分析和商品管理增删改查)
35 4
|
2天前
|
并行计算 Java API
|
4天前
|
前端开发 Oracle Java
Java 22 新增利器: 使用 Java Stream Gather 优雅地处理流中的状态
本文我们分析了 什么 是 “流”,对比了 Java 上几种常见的 “流”库,引入和详细介绍了 Java 22 中的 Stream Gather API 。同时也简单分享了利用 虚拟线程 如何简化 StreammapConcurrent操作符的实现。
|
4天前
|
Java API
Java8 Lambda 设计和实现问题之在Java 8的Stream API中,parallel=false时collect方法是如何实现的
Java8 Lambda 设计和实现问题之在Java 8的Stream API中,parallel=false时collect方法是如何实现的
|
5天前
|
Java
Java Lambda Stream
Java Lambda Stream
11 0
|
7天前
|
Java API 开发者
震撼!Java 8 中 Lambda 表达式与 Stream API 带来的编程革命超乎想象!
【8月更文挑战第12天】Java 8 引入了 Lambda 表达式和 Stream API,极大地提升了编程效率与代码可读性。Lambda 表达式简化了匿名函数的定义,如快速定义数学运算 `(a, b) -&gt; a + b`。Stream API 提供了一种声明式数据处理方式,能够流畅地完成过滤、映射等操作,减少循环结构的复杂性。两者结合,让 Java 代码更加简洁高效,易于理解和维护。
20 0