Java 中 Stream 流的用法全解析

在 Java 编程中,Stream 流提供了一种高效、便捷的方式来处理集合数据。它可以让我们以声明式的方式对数据进行各种操作,如过滤、映射、排序、聚合等,大大简化了数据处理的代码编写。本文将详细介绍 Java 中 Stream 流的用法,包括基础用法、中级用法、高级用法以及一些特殊方法的使用。

一、基础用法

1. 创建 Stream

  • 从集合创建 Stream:通过调用集合的 stream() 方法可以创建一个顺序流。例如:
List<String> list = Arrays.asList("apple", "banana", "cherry");
Stream<String> stream1 = list.stream();
  • 从数组创建 Stream:使用 Arrays.stream() 方法可以从数组创建流。例如:
String[] array = {"apple", "banana", "cherry"};
Stream<String> stream2 = Arrays.stream(array);

2. 中间操作

  • filter:过滤元素:使用 filter 方法可以根据指定的条件过滤流中的元素。例如,以下代码过滤出以 "a" 开头的字符串:
list.stream()
.filter(s -> s.startsWith("a"))
.forEach(System.out::println); // 输出: apple
  • map:转换元素:map 方法可以将流中的每个元素按照指定的函数进行转换。例如,将字符串转换为大写:
list.stream()
.map(String::toUpperCase)
.forEach(System.out::println); // 输出: APPLE BANANA CHERRY

3. 终止操作

  • forEach:遍历元素:forEach 方法用于遍历流中的每个元素并执行指定的操作。例如:
list.stream().forEach(System.out::println);
  • collect:收集结果到集合:collect 方法可以将流中的元素收集到指定的集合中。例如,收集长度大于 5 的字符串到一个新的列表中:
List<String> result1 = list.stream()
.filter(s -> s.length() > 5)
.collect(Collectors.toList()); // 或者使用 toList() 方法(Java 16 及以上版本)
List<String> result2 = list.stream()
.filter(s -> s.length() > 5)
.toList();

二、中级用法

1. 排序

  • sorted:自然排序或自定义排序:sorted 方法可以对流中的元素进行排序。如果元素实现了 Comparable 接口,可以直接使用无参的 sorted 方法进行自然排序。例如:
list.stream()
.sorted()
.forEach(System.out::println); // 输出: apple banana cherry

如果需要自定义排序规则,可以传入一个 Comparator 比较器。例如,按照字符串长度倒序排序:

list.stream()
.sorted(Comparator.reverseOrder())
.forEach(System.out::println); // 输出: cherry banana apple

2. 去重

使用 distinct 方法可以去除流中的重复元素。例如:
List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 4, 4, 5);
List<Integer> distinctNumbers = numbers.stream()
.distinct()
.toList();

3. 聚合操作

  • reduce:归约操作:reduce 方法可以对流中的元素进行归约操作,例如求和、求乘积等。例如,计算整数列表的总和:
Optional<Integer> sum = numbers.stream()
.reduce((a, b) -> a + b); // 可替换为.reduce(Integer::sum);
System.out.println(sum.get()); // 输出: 19

三、高级用法

1. 并行流

  • parallelStream:并行处理(提高效率):使用 parallelStream 方法可以创建一个并行流,它会在多个线程上并行处理流中的元素,提高处理效率。例如,计算满足条件的元素数量:
long count = list.parallelStream()
.filter(s -> s.length() > 5)
.count();

2. 短路操作

  • anyMatch、allMatch、noneMatch:短路匹配:这些方法用于在流中进行短路匹配操作。

    • anyMatch:只要流中有一个元素满足条件就返回true。例如:
boolean anyStartsWithA = list.stream()
.anyMatch(s -> s.startsWith("a"));
System.out.println(anyStartsWithA); // 输出: true
  • allMatch:只有流中所有元素都满足条件才返回 true。例如:
boolean allStartsWithA = list.stream()
.allMatch(s -> s.startsWith("a"));
System.out.println(allStartsWithA); // 输出: false
  • noneMatch:如果流中没有元素满足条件则返回 true。例如:
boolean noneStartsWithZ = list.stream()
.noneMatch(s -> s.startsWith("z"));
System.out.println(noneStartsWithZ); // 输出: true

3. 分组和分区

  • Collectors.groupingBy:分组:使用 groupingBy 方法可以根据指定的分类函数将流中的元素分组到一个 Map 中。例如,根据字符串的首字母进行分组:
Map<Character, List<String>> groupedByFirstLetter = list.stream()
.collect(Collectors.groupingBy(s -> s.charAt(0)));
System.out.println(groupedByFirstLetter); // {a=[apple], b=[banana], c=[cherry]}
  • Collectors.partitioningBy:分区:partitioningBy 方法根据指定的布尔条件将流中的元素分区到一个 Map 中,键为 true 和 false。例如,根据字符串长度是否大于 5 进行分区:
Map<Boolean, List<String>> partitioned = list.stream()
.collect(Collectors.partitioningBy(s -> s.length() > 5)); // {false=[apple], true=[banana, cherry]}
System.out.println(partitioned);

4. 收集到 Map

  • Collectors.toMap:收集到 Map:使用 toMap 方法可以将流中的元素收集到一个 Map 中,需要指定键和值的映射函数。例如:
Map<String, Integer> map = list.stream()
.collect(Collectors.toMap(Function.identity(), String::length));
System.out.println(map);

四、flatMap 用法

flatMap 方法用于将流中的每个元素转换为另一个流,然后将这些流扁平化成一个单一的流。这在处理嵌套集合时非常有用。例如:
List<List<String>> listOfLists = Arrays.asList(
Arrays.asList("apple", "banana"),
Arrays.asList("cherry", "date"),
Arrays.asList("fig", "grape")
); // 使用 flatMap 将嵌套列表扁平化
List<String> flattenedList = listOfLists.stream()
.flatMap(List::stream)
.collect(Collectors.toList()); System.out.println(flattenedList); // 输出: [apple, banana, cherry, date, fig, grape]

五、peek 用法

  • peek 方法主要用于调试,它允许你在流的每个元素上执行某个操作(例如打印),而不会改变流中的元素。peek 返回一个新的流,其中包含与原始流相同的元素。例如:
List<String> list = Arrays.asList("apple", "banana", "cherry");

List<String> result = list.stream()
.peek(s -> System.out.println("Processing: " + s)) // 打印每个元素
.map(String::toUpperCase)
.collect(Collectors.toList()); System.out.println(result); // 输出: [APPLE, BANANA, CHERRY]

六、limit 用法

  • limit 方法用于限制流中的元素数量。例如:
List<String> list = Arrays.asList("apple", "banana", "cherry", "date", "fig", "grape");

List<String> limitedList = list.stream()
.limit(3)
.collect(Collectors.toList()); System.out.println(limitedList); // 输出: [apple, banana, cherry]

七、skip 用法

  • skip 方法用于跳过流中的前 n 个元素。例如:
List<String> list = Arrays.asList("apple", "banana", "cherry", "date", "fig", "grape");

List<String> skippedList = list.stream()
.skip(3)
.collect(Collectors.toList()); System.out.println(skippedList); // 输出: [date, fig, grape]

八、min 和 max

  • min 和 max 方法用于查找流中的最小值和最大值。例如:
List<Integer> numbers = Arrays.asList(10, 20, 30, 40, 50);

// 查找最小值
Optional<Integer> min = numbers.stream()
.min(Integer::compareTo); System.out.println(min.get()); // 输出: 10 // 查找最大值
Optional<Integer> max = numbers.stream()
.max(Integer::compareTo); System.out.println(max.get()); // 输出: 50

九、findAny 和 findFirst

  • findAny 和 findFirst 方法用于查找流中的任意元素和第一个元素。例如:
List<String> list = Arrays.asList("apple", "banana", "cherry");

// 查找任意一个元素
Optional<String> anyElement = list.stream().findAny(); System.out.println(anyElement.get()); // 输出: apple (或 banana 或 cherry) // 查找第一个元素
Optional<String> firstElement = list.stream().findFirst(); System.out.println(firstElement.get()); // 输出: apple

通过以上对 Java 中 Stream 流的全面介绍,我们可以看到它在数据处理方面提供了强大而灵活的功能。合理运用 Stream 流可以使我们的代码更加简洁、高效,提高编程的效率和代码的可读性。在实际开发中,根据具体的需求选择合适的 Stream 流操作方法,可以更好地处理集合数据,实现复杂的数据处理逻辑。

在 Java 编程中,Stream 流提供了一种高效、便捷的方式来处理集合数据。它可以让我们以声明式的方式对数据进行各种操作,如过滤、映射、排序、聚合等,大大简化了数据处理的代码编写。本文将详细介绍 Java 中 Stream 流的用法,包括基础用法、中级用法、高级用法以及一些特殊方法的使用。

一、基础用法

1. 创建 Stream

  • 从集合创建 Stream:通过调用集合的 stream() 方法可以创建一个顺序流。例如:
收起
java
 
List<String> list = Arrays.asList("apple", "banana", "cherry");
Stream<String> stream1 = list.stream();
  • 从数组创建 Stream:使用 Arrays.stream() 方法可以从数组创建流。例如:
收起
java
 
String[] array = {"apple", "banana", "cherry"};
Stream<String> stream2 = Arrays.stream(array);

2. 中间操作

  • filter:过滤元素:使用 filter 方法可以根据指定的条件过滤流中的元素。例如,以下代码过滤出以 "a" 开头的字符串:
收起
java
 
list.stream()
.filter(s -> s.startsWith("a"))
.forEach(System.out::println); // 输出: apple
  • map:转换元素:map 方法可以将流中的每个元素按照指定的函数进行转换。例如,将字符串转换为大写:
收起
java
 
list.stream()
.map(String::toUpperCase)
.forEach(System.out::println); // 输出: APPLE BANANA CHERRY

3. 终止操作

  • forEach:遍历元素:forEach 方法用于遍历流中的每个元素并执行指定的操作。例如:
收起
java
 
list.stream().forEach(System.out::println);
  • collect:收集结果到集合:collect 方法可以将流中的元素收集到指定的集合中。例如,收集长度大于 5 的字符串到一个新的列表中:
收起
java
 
List<String> result1 = list.stream()
.filter(s -> s.length() > 5)
.collect(Collectors.toList()); // 或者使用 toList() 方法(Java 16 及以上版本)
List<String> result2 = list.stream()
.filter(s -> s.length() > 5)
.toList();

二、中级用法

1. 排序

  • sorted:自然排序或自定义排序:sorted 方法可以对流中的元素进行排序。如果元素实现了 Comparable 接口,可以直接使用无参的 sorted 方法进行自然排序。例如:
收起
java
 
list.stream()
.sorted()
.forEach(System.out::println); // 输出: apple banana cherry
如果需要自定义排序规则,可以传入一个 Comparator 比较器。例如,按照字符串长度倒序排序:
收起
java
 
list.stream()
.sorted(Comparator.reverseOrder())
.forEach(System.out::println); // 输出: cherry banana apple

2. 去重

使用 distinct 方法可以去除流中的重复元素。例如:
收起
java
 
List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 4, 4, 5);
List<Integer> distinctNumbers = numbers.stream()
.distinct()
.toList();

3. 聚合操作

  • reduce:归约操作:reduce 方法可以对流中的元素进行归约操作,例如求和、求乘积等。例如,计算整数列表的总和:
收起
java
 
Optional<Integer> sum = numbers.stream()
.reduce((a, b) -> a + b); // 可替换为.reduce(Integer::sum);
System.out.println(sum.get()); // 输出: 19

三、高级用法

1. 并行流

  • parallelStream:并行处理(提高效率):使用 parallelStream 方法可以创建一个并行流,它会在多个线程上并行处理流中的元素,提高处理效率。例如,计算满足条件的元素数量:
收起
java
 
long count = list.parallelStream()
.filter(s -> s.length() > 5)
.count();

2. 短路操作

  • anyMatch、allMatch、noneMatch:短路匹配:这些方法用于在流中进行短路匹配操作。

    • anyMatch:只要流中有一个元素满足条件就返回 true。例如:
收起
java
 
boolean anyStartsWithA = list.stream()
.anyMatch(s -> s.startsWith("a"));
System.out.println(anyStartsWithA); // 输出: true
  • allMatch:只有流中所有元素都满足条件才返回 true。例如:
收起
java
 
boolean allStartsWithA = list.stream()
.allMatch(s -> s.startsWith("a"));
System.out.println(allStartsWithA); // 输出: false
  • noneMatch:如果流中没有元素满足条件则返回 true。例如:
收起
java
 
boolean noneStartsWithZ = list.stream()
.noneMatch(s -> s.startsWith("z"));
System.out.println(noneStartsWithZ); // 输出: true

3. 分组和分区

  • Collectors.groupingBy:分组:使用 groupingBy 方法可以根据指定的分类函数将流中的元素分组到一个 Map 中。例如,根据字符串的首字母进行分组:
收起
java
 
Map<Character, List<String>> groupedByFirstLetter = list.stream()
.collect(Collectors.groupingBy(s -> s.charAt(0)));
System.out.println(groupedByFirstLetter); // {a=[apple], b=[banana], c=[cherry]}
  • Collectors.partitioningBy:分区:partitioningBy 方法根据指定的布尔条件将流中的元素分区到一个 Map 中,键为 true 和 false。例如,根据字符串长度是否大于 5 进行分区:
收起
java
 
Map<Boolean, List<String>> partitioned = list.stream()
.collect(Collectors.partitioningBy(s -> s.length() > 5)); // {false=[apple], true=[banana, cherry]}
System.out.println(partitioned);

4. 收集到 Map

  • Collectors.toMap:收集到 Map:使用 toMap 方法可以将流中的元素收集到一个 Map 中,需要指定键和值的映射函数。例如:
收起
java
 
Map<String, Integer> map = list.stream()
.collect(Collectors.toMap(Function.identity(), String::length));
System.out.println(map);

四、flatMap 用法

flatMap 方法用于将流中的每个元素转换为另一个流,然后将这些流扁平化成一个单一的流。这在处理嵌套集合时非常有用。例如:
收起
java
 
List<List<String>> listOfLists = Arrays.asList(
Arrays.asList("apple", "banana"),
Arrays.asList("cherry", "date"),
Arrays.asList("fig", "grape")
); // 使用 flatMap 将嵌套列表扁平化
List<String> flattenedList = listOfLists.stream()
.flatMap(List::stream)
.collect(Collectors.toList()); System.out.println(flattenedList); // 输出: [apple, banana, cherry, date, fig, grape]

五、peek 用法

peek 方法主要用于调试,它允许你在流的每个元素上执行某个操作(例如打印),而不会改变流中的元素。peek 返回一个新的流,其中包含与原始流相同的元素。例如:
收起
java
 
List<String> list = Arrays.asList("apple", "banana", "cherry");

List<String> result = list.stream()
.peek(s -> System.out.println("Processing: " + s)) // 打印每个元素
.map(String::toUpperCase)
.collect(Collectors.toList()); System.out.println(result); // 输出: [APPLE, BANANA, CHERRY]

六、limit 用法

limit 方法用于限制流中的元素数量。例如:
收起
java
 
List<String> list = Arrays.asList("apple", "banana", "cherry", "date", "fig", "grape");

List<String> limitedList = list.stream()
.limit(3)
.collect(Collectors.toList()); System.out.println(limitedList); // 输出: [apple, banana, cherry]

七、skip 用法

skip 方法用于跳过流中的前 n 个元素。例如:
收起
java
 
List<String> list = Arrays.asList("apple", "banana", "cherry", "date", "fig", "grape");

List<String> skippedList = list.stream()
.skip(3)
.collect(Collectors.toList()); System.out.println(skippedList); // 输出: [date, fig, grape]

八、min 和 max

min 和 max 方法用于查找流中的最小值和最大值。例如:
收起
java
 
List<Integer> numbers = Arrays.asList(10, 20, 30, 40, 50);

// 查找最小值
Optional<Integer> min = numbers.stream()
.min(Integer::compareTo); System.out.println(min.get()); // 输出: 10 // 查找最大值
Optional<Integer> max = numbers.stream()
.max(Integer::compareTo); System.out.println(max.get()); // 输出: 50

九、findAny 和 findFirst

findAny 和 findFirst 方法用于查找流中的任意元素和第一个元素。例如:
收起
java
 
List<String> list = Arrays.asList("apple", "banana", "cherry");

// 查找任意一个元素
Optional<String> anyElement = list.stream().findAny(); System.out.println(anyElement.get()); // 输出: apple (或 banana 或 cherry) // 查找第一个元素
Optional<String> firstElement = list.stream().findFirst(); System.out.println(firstElement.get()); // 输出: apple
通过以上对 Java 中 Stream 流的全面介绍,我们可以看到它在数据处理方面提供了强大而灵活的功能。合理运用 Stream 流可以使我们的代码更加简洁、高效,提高编程的效率和代码的可读性。在实际开发中,根据具体的需求选择合适的 Stream 流操作方法,可以更好地处理集合数据,实现复杂的数据处理逻辑。

[Java] Stream流使用最多的方式的更多相关文章

  1. 全面吃透JAVA Stream流操作,让代码更加的优雅

    全面吃透JAVA Stream流操作,让代码更加的优雅 在JAVA中,涉及到对数组.Collection等集合类中的元素进行操作的时候,通常会通过循环的方式进行逐个处理,或者使用Stream的方式进行 ...

  2. 一文带你入门Java Stream流,太强了

    两个星期以前,就有读者强烈要求我写一篇 Java Stream 流的文章,我说市面上不是已经有很多了吗,结果你猜他怎么说:"就想看你写的啊!"你看你看,多么苍白的喜欢啊.那就&qu ...

  3. Java Stream 流如何进行合并操作

    1. 前言 Java Stream Api 提供了很多有用的 Api 让我们很方便将集合或者多个同类型的元素转换为流进行操作.今天我们来看看如何合并 Stream 流. 2. Stream 流的合并 ...

  4. Java | Stream流、泛型、多线程 | 整理自用

    1.lambda 表达式 lambda 的延迟执行 可以对程序进行优化,尤其是使用 if {} else {} 条件判断,先判断条件是否成立,再传入计算好的参数. functionName( para ...

  5. 深度掌握 Java Stream 流操作,让你的代码高出一个逼格!

    概念 Stream将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行操作,比如:筛选.排序.聚合等. Stream 的操作符大体上分为两种:中间操作符和终止操作符 中 ...

  6. Java Stream流的使用

    流相关的方法可以分为三种类型,分别是:获取Stream流.中间方法.终结方法.中间方法会返回当前流,可以方便的进行链式调用. 流不可重复使用,否则会报错: java.lang.IllegalState ...

  7. Java Stream流

    Java8 Stream流编程 Stream 使用一种类似于SQL语句从数据库查询数据的直观方式来提供对 Java 集合运算和表达的高阶抽象.得益于 Lambda 所带来的函数式编程,Stream A ...

  8. Java Stream 流(JDK 8 新特性)

    什么是 Steam Java 8 中新增了 Stream(流)来简化集合类的使用,Stream 本质上是个接口,接口中定义了很多对 Stream 对象的操作. 我们知道,Java 中 List 和 S ...

  9. Java Stream流排序null以及获取指定条数数据

    Java8的Stream流的一些用法, //排序 carerVehEntityList = carerVehEntityList.stream().sorted( Comparator.compari ...

  10. Java Stream简介, 流的基本概念

    在Javaor .net编程中,  我们经常见到"stream" 这个字眼. 我们大概知道这是个流的意思, 如果看完本文的话, 应该会有1个大概的概念. 一, Java中什么是St ...

随机推荐

  1. 全网最适合入门的面向对象编程教程:53 Python 字符串与序列化-字符串与字符编码

    全网最适合入门的面向对象编程教程:53 Python 字符串与序列化-字符串与字符编码 摘要: 在 Python 中,字符串是文本的表示,默认使用 Unicode 编码,这允许你处理各种字符集,字符编 ...

  2. pinia - 为 antdv 表格添加加载状态

    前言 我们之前制作的 Vue3 + AntDesign Vue + SpringBoot 的增删改查小 Demo 的功能已经全部实现了,但是还是有一点不完美,在发送请求到后端返回数据这一段时间内前台未 ...

  3. o1 式开源推理链项目 g1:可基于 Llama 3.2-90b 模型

    g1 简介 g1 是一个开源项目,利用 Llama 3.1 70b 模型在 Groq 硬件上实现类似 OpenAI o1 的推理链能力.项目通过精心设计的提示策略引导语言模型进行逐步推理,解决了传统语 ...

  4. 2020年度国产数据库:openGauss

    根据墨天轮2020年一年的数据库流行度得分趋势变化,我们选出了流行热度增长显著的数据库为2020年度国产数据库.恭喜 华为开源关系型数据库 openGauss 荣获 "2020年度国产数据库 ...

  5. vue前端开发仿钉图系列(6)左侧记事本的开发详解

    在页面开发中,深深的被element组件所吸引,里面很多小组件都可以直接使用.像是记事本提示.记事本列表时间线.右侧编辑页面的form表单,编辑和查看状态的切换等等,比之前iOS原生开发所有的东西都要 ...

  6. base64 是什么,有什么作用?

    base64 是图片编码的一种形式,可以替代图片的url进行网络访问和请求等操作: 使用图片的url形式操作图片,每次都要请求一次网络,因为每次请求都是一个http:都是一个网络开销,都是对服务器的负 ...

  7. 2021年华为Java面试真题解析,帮你解决95%以上的问题!

    前言 由于作者面试过程中高度紧张,本文中只列出了自己还记得的部分题目. 经历了漫长一个月的等待,终于在前几天通过面试官获悉已被蚂蚁金服录取,这期间的焦虑.痛苦自不必说,知道被录取的那一刻,一整年的阴霾 ...

  8. Mysql(1)—简介及Windows环境下载安装

    Mysql(1)-简介及Windows环境下载安装 一.关于Mysql 1.1 简介 MySQL是一个流行的关系型数据库管理系统(RDBMS),它基于结构化查询语言(SQL)进行操作.MySQL由瑞典 ...

  9. 大便系统无法使用source的原因及解决方法

    debian中shell脚本无法使用source的原因及解决方法 现象: shell脚本中source aaa.sh时提示 source: not found 原因: ls -l `which sh` ...

  10. mysql热迁移

    0.背景 XtraBackup 优势 在线热备:支持在不停止数据库的情况下进行 InnoDB 和 XtraDB 的热备份,适合高可用环境. 增量备份:支持增量备份,能够显著减少备份时间和存储空间需求. ...