当前位置: 首页 > news >正文

Java——Stream流

平时处理集合、数组,是不是都这么写?定义一个 List,然后写个 for 循环遍历,加 if 判断,过滤数据,再把符合条件的装进新集合,最后再循环输出,这样写十分复杂

自从 Java 8 出了 Stream 流之后,这一切都变了。以前五六行、十几行才能做完的事,现在一行代码搞定。过滤、去重、排序、映射、统计、分组、收集…… 所有你能想到的集合操作,Stream 流几乎都能一条龙解决。


一、Stream定义

Stream 不是集合,不是数据结构,它不存数据,它只是一个 “加工工具”

你可以把它理解成:工厂流水线

  • 集合 / 数组 → 原材料
  • Stream → 流水线
  • 中间操作(过滤、去重、排序) → 加工步骤
  • 终结操作(输出、收集、统计) → 成品出厂

它的工作流程特别简单:

  1. 把集合 / 数组变成一条 “流”
  2. 在流上做各种操作(想怎么加工就怎么加工)
  3. 最后拿到你想要的结果

而且 Stream 有一个很重要的特点:用完就丢,只能用一次。就像矿泉水,你打开喝了就没了,不能倒回去再喝一遍。

再记住一句话:Stream 只负责处理数据,不改变原数据你原来的集合是什么样,处理完还是什么样,不会被修改,这一点特别安全。


二、Stream的优点

1. 代码简洁

以前遍历过滤一个集合:

List<String> list = new ArrayList<>(); for (String s : oldList) { if (s != null && s.length() > 3) { list.add(s); } }

用 Stream:

List<String> list = oldList.stream() .filter(s -> s != null && s.length() > 3) .collect(Collectors.toList());

2. 支持链式编程

list.stream() .filter(...) .map(...) .distinct() .sorted() .collect(...);

从上到下,一步一步, 代码一目了然。


三、Stream 最核心的两个概念

用 Stream 之前,需要记住两个词:中间操作终结操作

1. 中间操作(加工)

  • 比如:过滤 filter、映射 map、去重 distinct、限制 limit、跳过 skip、排序 sorted
  • 特点:可以连着写多个,不会真正执行
  • 就像你在流水线设置好加工步骤,机器还没开动

2. 终结操作(出厂)

  • 比如:遍历 forEach、收集 collect、计数 count、判断 anyMatch、转数组 toArray
  • 特点:只要一执行,整个流才开始跑
  • 执行完,流就关闭了,不能再用

一句话总结:只有调用终结操作,前面的中间操作才会执行;不调用终结操作,等于啥也没干。


四、第一步:怎么获取 Stream 流?(3 种最常用方式)

想使用 Stream,第一步必须先把数据变成 “流”。常用的就 3 种,记这 3 种足够用。

1. 集合 Collection 直接获取(最常用)

List、Set 都能用:

List<String> list = new ArrayList<>(); Stream<String> stream = list.stream(); Stream<String> parallelStream = list.parallelStream();

2. 数组用 Arrays.stream ()

String[] arr = {"张三","李四","王五"}; Stream<String> stream = Arrays.stream(arr);

3. 零散数据用 Stream.of ()

Stream<String> stream = Stream.of("张三","李四","王五","赵六");

五、Stream 常用中间操作:

1. filter:过滤

作用:只留下符合条件的数据参数:一个返回 boolean 的条件,true 留下,false 扔掉

例子:过滤出长度大于 3 的字符串

List<String> list = Stream.of("aa","bbb","cccc","ddddd") .filter(s -> s.length() > 3) .collect(Collectors.toList()); // 结果:cccc、ddddd

2. map:转换

作用:把一种数据,转成另一种数据比如:String 转 Integer、对象转名字、对象转 ID、数字转平方

例子 1:字符串转长度

List<Integer> lengths = Stream.of("张三","张三丰","孙悟空") .map(s -> s.length()) .collect(Collectors.toList()); // 结果:2、3、3

例子 2:用户对象转用户名

List<String> names = userList.stream() .map(user -> user.getName()) .collect(Collectors.toList());

3. distinct:去重

作用:自动去掉重复数据底层用的 equals () 判断,简单粗暴。

List<Integer> list = Stream.of(1,2,2,3,3,3) .distinct() .collect(Collectors.toList()); // 结果:1、2、3

4. sorted:排序

作用:给数据排序两种用法:

  • 无参:自然排序(数字从小到大、字符串按字典序)
  • 有参:自定义排序

例子 1:自然排序

List<Integer> list = Stream.of(3,1,5,2,4) .sorted() .collect(Collectors.toList()); // 1、2、3、4、5

例子 2:倒序

.sorted((a,b) -> b - a)

例子 3:按对象字段排序

.sorted(Comparator.comparing(User::getAge))

5. limit:限制取前几个

作用:只取前 N 个

List<Integer> list = Stream.of(1,2,3,4,5) .limit(3) .collect(Collectors.toList()); // 1、2、3

6. skip:跳过前几个

作用:跳过前 N 个,取后面的

List<Integer> list = Stream.of(1,2,3,4,5) .skip(2) .collect(Collectors.toList()); // 3、4、5

六、Stream 常用终结操作:执行才是硬道理

中间操作设置完,必须调用终结操作,否则代码不执行

1. forEach:遍历

作用:一个一个拿出来处理

Stream.of("张三","李四").forEach(s -> System.out.println(s));

2. collect:收集

作用:把流转成集合、字符串、数组这是最强大的终结操作,必须会。

常用收集方式:

  • 转 List:Collectors.toList()
  • 转 Set:Collectors.toSet()
  • 转 Map:Collectors.toMap(键,值)
  • 拼接字符串:Collectors.joining(",")
  • 分组:Collectors.groupingBy(字段)
  • 统计:Collectors.counting()Collectors.summingInt()

3. count:计数

作用:统计流里有多少个元素

long count = Stream.of(1,2,3).count(); // 3

4. anyMatch:任意一个匹配

作用:只要有一个符合条件,就返回 true

boolean has = Stream.of(1,2,3).anyMatch(s -> s > 2); // true

5. allMatch:全部匹配

作用:所有元素都符合条件才返回 true

6. noneMatch:全都不匹配

作用:一个都不符合才返回 true

7. findFirst:找第一个

作用:返回第一个元素

Optional<String> first = Stream.of("a","b").findFirst();

8. toArray:转数组

作用:流转数组

String[] arr = Stream.of("a","b").toArray(String[]::new);

七、Collectors 工具类:Stream 最强辅助

1. 转 List / Set

collect(Collectors.toList()); collect(Collectors.toSet());

2. 转 Map

注意:键不能重复,否则报错。

Map<Integer, User> map = userList.stream() .collect(Collectors.toMap(User::getId, user -> user));

3. 字符串拼接

把所有元素用符号连起来,超级好用。

String str = Stream.of("张三","李四","王五") .collect(Collectors.joining(",")); // 张三,李四,王五

4. 分组

按某个字段分组,比如按年龄、性别、部门。

Map<Integer, List<User>> map = userList.stream() .collect(Collectors.groupingBy(User::getAge));

结果:key 是年龄,value 是这个年龄的所有人。

5. 统计:最大值、最小值、平均值、总和

// 总和 int sum = userList.stream().collect(Collectors.summingInt(User::getAge)); // 最大值 OptionalInt max = userList.stream().mapToInt(User::getAge).max(); // 平均值 double avg = userList.stream().mapToInt(User::getAge).average().orElse(0);

八、真实案例:

案例 1:过滤 + 转换 + 去重 + 排序 + 收集

需求:从用户列表中,过滤出年龄大于 18 岁的,提取名字,去重,按字典序排序,最后转成 List。

List<String> result = userList.stream() .filter(user -> user.getAge() > 18) .map(User::getName) .distinct() .sorted() .collect(Collectors.toList());

案例 2:根据条件判断是否存在数据

boolean has = userList.stream() .anyMatch(user -> "张三".equals(user.getName()));

案例 3:把 List 转成用逗号分隔的字符串

String str = list.stream().collect(Collectors.joining(","));

案例 4:根据性别分组

Map<String, List<User>> group = userList.stream() .collect(Collectors.groupingBy(User::getSex));

九、Stream 和 普通 for 循环怎么选?

  1. 简单遍历、简单逻辑→ for 循环和 Stream 都行
  2. 过滤、转换、去重、排序、统计、分组→ 优先 Stream,代码简洁
  3. 极度追求性能、超小数据量→ for 循环稍微快一丢丢,但几乎可以忽略
  4. 复杂嵌套逻辑、多跳出条件→ for 循环更清晰

简单说:能使用 Stream 的场景,尽量用 Stream,代码好看、好维护、好改。


十二、总结:

  1. Stream 是数据加工工具,不存数据,不修改原数据
  2. 流只能用一次,用完即关闭
  3. 中间操作不执行,只有终结操作才触发执行
  4. filter 过滤、map 转换、distinct 去重、sorted 排序
  5. collect 收集是最强大的终结操作
  6. Collectors 可以转 List、Set、Map、分组、拼接、统计
  7. 并行流适合大数据量处理
  8. 不要在 Stream 里修改外部变量
  9. toMap 注意键重复问题
  10. 能用 Stream 就用 Stream,代码简洁易维护
http://www.jsqmd.com/news/706346/

相关文章:

  • Devart数据连接工具全解析与26周年庆优惠指南
  • 定义类的方法和CRC建模
  • AI Agent 面试题 015:如何实现Agent的多模态感知能力?
  • SwiftLLM:专为研究设计的轻量级LLM推理引擎
  • python缺陷检测
  • 彻底搞懂:Spring Boot/Cloud 中 bootstrap.yml 与 application.yml 的区别与最佳实践
  • 机器学习分类算法实战:5大核心方法详解
  • 大语言模型偏见检测:统计方法与工程实践
  • 1 6.2 设置成员的访问时间(屏幕时间 / 跨设备日程一致)
  • AI Agent 面试题 016:Agent的决策过程中如何平衡探索与利用?
  • AI Agent生产环境压测指南:并发、延迟与资源瓶颈定位
  • 设计Section 12:Related PCB Assembly Services
  • R语言描述性统计:数据分析基础与实战技巧
  • Docker学习路径——6、Docker 微服务基础实战:Tomcat + MySQL + Redis 一站式部署指南
  • R语言机器学习实战:10大内置数据集应用指南
  • 基于PraisonAI的多智能体编排框架:从YAML配置到生产部署全解析
  • DeepLabv3+:融合空洞可分离卷积的编码器-解码器语义分割架构
  • gws:Google Workspace命令行工具,为AI自动化而生
  • Cursor Stats Extension:为AI编程助手打造数据可视化仪表盘
  • LLMStack:低代码平台如何简化大模型应用开发与RAG系统构建
  • 【3D】VTK-Ubuntu22.04安装VTK
  • AI日报:24小时全球科技热点速览
  • 2026如何选牛牛加速厂家:牛牛ip、牛牛加速、宽带多拨、模拟器、短效IP、静态IP、SDK包、http、socks5选择指南 - 优质品牌商家
  • 2026年平衡泥技术解析:平衡泥厂家、平衡泥品牌、平衡泥工厂、动平衡泥、平衡泥公司、平衡泥厂商、平衡土、高比重平衡胶泥选择指南 - 优质品牌商家
  • 基于用户行为数据的留存动因分析与预警策略研究
  • 【风暴之城】游玩日记 新手攻略(2)
  • 为Open WebUI构建安全代码执行沙箱:基于gVisor的本地LLM增强方案
  • 这些AI编曲软件到底强在哪,2026年度甄选5款AI编曲软件汇总,高质量助力音乐人制作编曲伴奏
  • 自洽性与Agent的结合
  • DeepSeek-V4-Pro API降价实测