Java Stream流

什么是流(Stream)?

流是 Java 8 引入的一种新特性 ,它为操作集合(如 List、Set)提供了一种更加声明性和函数式的方式。你可以把它看作是 对集合数据的处理管道。

与传统的基于循环(如 for)的方式不同,流允许你以一种更简洁、更直观的方式来处理数据。流的一个核心思想就是:声明你想要做什么,而不需要关心如何去做(即不需要关心具体的实现细节)。

流可以做的事情包括:

流的组成部分

  • 遍历集合。
  • 过滤集合中的元素。
  • 转换集合中的元素。
  • 排序集合中的元素。
  • 组合多种操作。

流的关键特性

  • 惰性求值(Lazy Evaluation) :流操作是惰性执行的,意味着它们不会立即执行,直到你调用终结操作(例如 collect()、forEach())时才会开始实际的计算。
  • 可以链式调用:流支持方法链的调用,你可以在一行代码中进行多种操作,如过滤、映射、排序等。
  • 无副作用:流操作不会修改原始数据源,而是返回一个新的流或结果。
  • 源(Source) :流的起点,通常是一个集合(如 List、Set)、数组、文件等。
  • 中间操作(Intermediate Operations) :对流中的元素进行转换或过滤,返回一个新的流。常见的中间操作有 filter()、map()、sorted() 等。
  • 终结操作(Terminal Operations) :执行实际的计算,通常会产生一个结果。常见的终结操作有 collect()、forEach()、reduce() 等。

举个例子:传统方法 vs 流(Stream)

传统方法

假设你有一个 List,想要找出所有年龄大于 18 的用户,并将他们的名字转换为大写。

使用传统的 for-each 循环:

java 复制代码
List<User> users = getUsers();
List<String> result = new ArrayList<>();
for (User user : users) {
    if (user.getAge() > 18) {
        result.add(user.getName().toUpperCase());
    }
}

上面的代码,使用了显式的 for 循环,检查每个 User 是否符合条件,然后手动添加到结果列表中。

使用流(Stream)的方法

使用 流 来实现相同的操作:

java 复制代码
List<String> result = users.stream()
    .filter(user -> user.getAge() > 18)  // 过滤出年龄大于18的用户
    .map(user -> user.getName().toUpperCase())  // 转换成大写
    .collect(Collectors.toList());  // 收集到一个列表中

流的方式相比传统方式更加简洁和声明性,代码更短,逻辑更加清晰。每个操作(如 filter 和 map)都是链式调用,直接表达了你想要做什么:过滤、转换、收集。

流的工作原理

1. Stream 的源:

流通常来源于一个集合,如 List、Set、数组、甚至是文件等。例如,users.stream() 就是把 users 列表转成了一个流。

2. 中间操作:

流的中间操作不会立即执行,它们会返回一个新的流对象。中间操作通常是用于变换流中的数据。常见的中间操作有:

  • map():转换每个元素(例如将字符串转换成大写)。
  • filter():过滤出符合条件的元素。
  • sorted():对流中的元素进行排序。
3. 终结操作:

终结操作会触发流的实际计算,并且通常会产生一个结果。常见的终结操作有:

  • collect():将流中的元素收集到一个集合中。
  • forEach():对每个元素执行一个动作。
  • reduce():将流中的元素聚合成一个单一的结果。

对**forEach, reduce方法的解释**

a. forEach():对每个元素执行一个动作

forEach() 是流的终结操作,用于遍历流中的每个元素,并对每个元素执行指定的操作。它常用于执行副作用(如打印、更新外部状态等)。

示例:
java 复制代码
List<String> names = List.of("Alice", "Bob", "Charlie");
​
names.stream()
    .forEach(name -> System.out.println(name.toUpperCase()));

输出:

复制代码
ALICE
BOB
CHARLIE

这里,forEach() 遍历 names 流的每个元素,将其转换为大写并打印。

b. reduce():将流中的元素聚合成一个单一的结果

reduce() 是流的终结操作,用于将流中的元素通过某种方式聚合成一个最终的结果,通常是通过一个二元操作符(例如加法、乘法等)。

示例:求和
java 复制代码
List<Integer> numbers = List.of(1, 2, 3, 4, 5);
​
int sum = numbers.stream()
    .reduce(0, (a, b) -> a + b);
​
System.out.println(sum);  // 输出 15
  • 起始值 :0 是聚合的初始值。

  • 累加器 :(a, b) -> a + b 是一个累加操作,它将流中的元素两两相加。

示例:连接字符串
java 复制代码
List<String> words = List.of("Hello", "World", "Java");
​
String sentence = words.stream()
    .reduce("", (a, b) -> a + " " + b);
​
System.out.println(sentence);  // 输出 "Hello World Java"
  • 初始值:"" 是连接的起始字符串。

  • 累加器:(a, b) -> a + " " + b 用空格连接每个字符串。

总结
  • forEach():用于遍历流中的每个元素,并对每个元素执行某种操作(如打印、修改外部状态等)。

  • reduce():用于将流中的元素通过某种逻辑聚合成一个单一的结果,如求和、连接字符串等。

相关推荐
wangchunyu1141 小时前
JAVA CompletableFuture异步编程实战
java·开发语言·python
paopaokaka_luck2 小时前
流浪动物救助与收养系统(DeepSeek AI对话、 ECharts多维分析、救助流程衔接、领养与回访衔接、 捐赠确认与公示、志愿者协作)
java·前端·javascript·人工智能·mysql·echarts·推荐算法
Thomas.Sir2 小时前
第9课:SpringBoot4.x Web开发基础:WebMvc自动配置、静态资源、请求参数接收
java·spring boot
程序 代码狂人2 小时前
切片表与分区表的区别(数据开发面试版)
java·大数据·开发语言·数据仓库·算法
2501_944521593 小时前
Deepmerge 跨端三方库仓颉适配全流程
java·python·eclipse·github
meiying88383 小时前
快递单号批量查询Python脚本:从手动到自动化的完整实现
开发语言·python·自动化
@大迁世界4 小时前
告别 Go,拥抱 Rust
开发语言·golang·rust
SEO_juper4 小时前
Node.js 重定向链检测工具:301 跳了几跳、有没有成环,一次看清
xml·开发语言·python·node.js·json·bash
南归北隐4 小时前
Spring AI Alibaba Graph框架实现MCP数据库查询实战
java·后端·spring ai·mcp·spring ai mcp
学逆向的4 小时前
C 指针常量与常量指针
c语言·开发语言·网络安全