从Stream的 toList() 和 collect(Collectors.toList()) 方法看Java的不可变流

news2024/12/26 20:58:26

环境

  • JDK 21
  • Windows 11 专业版
  • IntelliJ IDEA 2024.1.6

背景

在使用Java的Stream的时候,常常会把流收集为List。

假设有List list1 如下:

        var list1 = List.of("aaa", "bbbbbb", "cccc", "d", "eeeee");

要找到所有长度大于3的字符串。

Java 8的做法是:

        var list2 = list1.stream().filter(e -> e.length() > 3).collect(Collectors.toList());

但是IDEA会给出一个提示:

‘collect(toList())’ can be replaced with ‘toList()’

如下图所示:

在这里插入图片描述
可见,代码可以简化如下:

        var list3 = list1.stream().filter(e -> e.length() > 3).toList();

注意: toList() 方法是Java 16引入的。

区别

虽然 collect(Collectors.toList())toList() 方法都返回List,但是二者是有一些差异的。

前者返回的一般是一个ArrayList,是可以修改的,而后者返回的是一个不可修改的List。

如下图所示:

在这里插入图片描述

可见,如果尝试给 list3 添加元素,IDEA会提示:

Immutable object is modified

注意:编译并不会报错,因为 list3 是List,调用 add() 方法是OK的,但是在运行期,会抛出 UnsupportedOperationException 异常:

Exception in thread "main" java.lang.UnsupportedOperationException
	at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:142)
	at java.base/java.util.ImmutableCollections$AbstractImmutableCollection.add(ImmutableCollections.java:147)
	at org.example.Test1119_41.main(Test1119_41.java:17)

同理,使用 list3.set() 方法来改变元素的值,也会在运行期抛出异常。

原因

把Stream收集为List是一个非常常用的操作,最初,Java 8提供了 collect(Collectors.toList()) 方法,显然,因为这个操作太常用了,所以在Java 16里,将其简化为了 toList() 方法。那么问题来了:

为什么Java 8里返回的是ArrayList,而Java 16简化后,返回的是不可变List呢?

咨询了豆包,它的回答里提到好几点,比如防止意外修改,线程安全,可维护性等等,不过下面这一点我觉得最有意义:

Java 8 引入了函数式编程特性,如流(Stream)和 Lambda 表达式。在函数式编程范式中,数据的不可变性是一个重要原则。函数式编程强调无副作用的操作,不可变数据结构符合这一要求。例如,在使用流操作(如map、filter等)处理数据时,不可变列表可以保证在每一步操作中,数据的原始状态不会被改变,使得流操作的结果更加可预测和符合函数式编程的语义。

说的挺有道理的。那么问题又来了:

既然在函数式编程中,数据的不可变性很重要,很有意义,那为什么不在最初Java 8的时候, collect(Collectors.toList()) 就返回不可变List呢?

答案是:Java语言一直在演进。

在Java 8的时候,对于数据不可变性的强调还没有像 Java 9 及以后那样深入。随着对函数式编程理念的深入理解,以及在实际应用中对数据安全、代码质量等方面的更高要求,Java 设计团队逐渐认识到不可变数据结构的重要性,从而在 Java 9 及后续版本中开始大力推广和完善不可变列表等相关特性。

当然,考虑到兼容性,Java高版本不可能把 collect(Collectors.toList()) 方法的返回值修改为不可变List。

话说回来,可变List也是必要的需求。即使不可变List是主流,总会有需求要对List做修改的。

其它

Arrays.asList() 和 List.of()

本文开头有如下代码:

        var list1 = List.of("aaa", "bbbbbb", "cccc", "d", "eeeee");

这里, List.of() 方法是Java 9引入的,返回的是一个不可变List

相应的,从Java 1.2就引入的 Arrays.asList() 方法:

        var list2 = Arrays.asList("aaa", "bbb", "ggg", "ddd", "eee", "fff");

它返回的是一个受限的可变List:不能改变List的长度,只能改变元素的值:

        list2.set(3, "hhh"); // OK
        list2.add("iii"); // UnsupportedOperationException

反序(注意不是排序中的逆序)

给定一个List或Stream,如何获取反序的List或Stream(比如把 "a", "c", "b" 变成 "b", "c", "a" )?

好像没有什么特别简单的办法,一个办法是利用 Collections.reverse() 方法,比如:

        Collections.reverse(list2);

这时问题就来了,对于不可变List,没法直接reverse,只能:

  1. 先克隆成可变List
  2. 再反序
  3. 最后再克隆成不可变List(如果需要的话)
        var list3 = new ArrayList<>(list1);
        Collections.reverse(list3);
        var list4 = List.of(list3);

对于Stream,更是没办法,只能先收集成可变List,再反序(或者在收集时,使用一些手段来人工处理,更麻烦)。

为什么Stream没有提供一个反序的方法呢?这可能也是因为函数式编程的理念吧:专注于对流的数据处理,而不是改变顺序(会误认为新数据是从对应位置的原始数据变化而来的)。

总结

collect(Collectors.toList())toList()
返回值一般是ArrayList不可变List
JDK版本816
适用场景后续需要修改数据典型的流式处理
是否推荐NY

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2245693.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大语言模型---LoRA简介;LoRA的优势;LoRA训练步骤;总结

文章目录 1. 介绍2. LoRA的优势3. LoRA训练步骤&#xff1a;4.总结 1. 介绍 LoRA&#xff08;Low-Rank Adaptation&#xff09;是一种用于高效微调大模型的技术&#xff0c;它通过在已有模型的基础上引入低秩矩阵来减少训练模型时所需的参数量和计算量。具体来说&#xff0c;L…

Debug-031-近期功能实现小结

由于时间原因&#xff0c;没办法对每个小的功能点进行比较细致的总结&#xff0c;这里统一去记录一下最近的实现了的功能&#xff0c;算是存档备份&#xff0c;为今后开发带来便利和参考。 一、ACEeditor ACEeditor使用手册&#xff08;一&#xff09;_ace editor-CSDN博客 AC…

深度学习中的mAP

在深度学习中&#xff0c;mAP是指平均精度均值(mean Average Precision)&#xff0c;它是深度学习中评价模型好坏的一种指标(metric)&#xff0c;特别是在目标检测中。 精确率和召回率的概念&#xff1a; (1).精确率(Precision)&#xff1a;预测阳性结果中实际正确的比例(TP / …

基于SpringBoot+Vue的影院管理系统(含演示视频+运行截图+说明文档)

web启动链接地址&#xff1a; http://localhost:8082&#xff08;管理端&#xff09; http://localhost:8081&#xff08;用户端&#xff09; http://localhost:8082&#xff08;员工端&#xff09; 一、项目介绍 基于框架的系统&#xff0c;系统分为用户、员工和管理员三个…

科研实验室的数字化转型:Spring Boot系统

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理实验室管理系统的相关信息成为必然。开发合…

网络无人值守批量装机-cobbler

网络无人值守批量装机-cobbler 一、cobbler简介 ​ 上一节中的pxe+kickstart已经可以解决网络批量装机的问题了,但是环境配置过于复杂,而且仅针对某一个版本的操作系统进批量安装则无法满足目前复杂环境的部署需求。 ​ 本小节所讲的cobbler则是基于pxe+kickstart技术的二…

基于Java Springboot二手商品网站

一、作品包含 源码数据库全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue、Element-ui 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 数据库&#xff1a;…

使用chrome 访问虚拟机Apache2 的默认页面,出现了ERR_ADDRESS_UNREACHABLE这个鸟问题

本地环境 主机MacOs Sequoia 15.1虚拟机Parallels Desktop 20 for Mac Pro Edition 版本 20.0.1 (55659)虚拟机-操作系统Ubuntu 22.04 服务器版本 最小安装 开发环境 编辑器编译器调试工具数据库http服务web开发防火墙Vim9Gcc13Gdb14Mysql8Apache2Php8.3Iptables 第一坑 数…

java: spire.pdf.free 9.12.3 create pdf

可以用windows 系统中文字体&#xff0c;也可以从文件夹的字体文件 /*** encoding: utf-8* 版权所有 2024 ©涂聚文有限公司* 许可信息查看&#xff1a;言語成了邀功盡責的功臣&#xff0c;還需要行爲每日來值班嗎* 描述&#xff1a;* # Author : geovindu,Geovin Du 涂…

PSO融合DWA路径规划(附MATLAB源代码)

PSO&#xff08;粒子群优化算法&#xff09;和DWA&#xff08;动态窗口法&#xff09;是路径规划领域常用的两种算法&#xff0c;它们结合使用可以充分发挥各自的优势&#xff0c;实现高效且安全的机器人路径规划。 1. PSO算法的全局路径规划 - 工作原理&#xff1a;PSO模拟群…

双因子认证:统一运维平台安全管理策略

01双因子认证概述 双因子认证&#xff08;Two-Factor Authentication&#xff0c;简称2FA&#xff09;是一种身份验证机制&#xff0c;它要求用户提供两种不同类型的证据来证明自己的身份。这通常包括用户所知道的&#xff08;如密码&#xff09;、用户所拥有的&#xff08;如…

蓝桥杯每日真题 - 第19天

题目&#xff1a;&#xff08;费用报销&#xff09; 题目描述&#xff08;13届 C&C B组F题&#xff09; 解题思路&#xff1a; 1. 问题抽象 本问题可以看作一个限制条件较多的优化问题&#xff0c;核心是如何在金额和时间约束下选择最优方案&#xff1a; 动态规划是理想…

MyBatis实践:提高持久化层数据处理效率

一、MyBatis简介: 1.简介:https://mybatis.org/mybatis-3/zh/index.html?spmwolai.workspace.0.0.66162306mX2SuC MyBatis最初是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation迁移到了Google Code。随着开发团队转投Google Code旗下&#xff…

HTML5实现剪刀石头布小游戏(附源码)

文章目录 1.设计来源1.1 主界面1.2 皮肤风格1.2 游戏中界面 2.效果和源码源码下载万套模板&#xff0c;程序开发&#xff0c;在线开发&#xff0c;在线沟通 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/143798520 HTM…

Three.js + AI:AI 算法生成 3D 萤火虫飞舞效果~

AI 驱动 3D 动画 大家好&#xff0c;我是石小石&#xff01;随着 Web 技术的发展&#xff0c;Three.js 成为构建 3D 图形和动画的主流工具。与此同时&#xff0c;人工智能&#xff08;AI&#xff09;在图像处理、动作生成等领域表现出强大能力。将 AI 与 Three.js 结合&#x…

如何判断注入点传参类型--理论

注入点传参类型 在我们找到注入点后&#xff0c;首先要判断传参的类型&#xff0c;才能以正确的形式向数据库查询数据。 注入点传参一般分为数字型和字符型。 数字型&#xff1a;当传入的参数为整形时&#xff0c;存在SQL注入漏洞&#xff0c;就可以认为是数字型注入。 字符…

01_初识GeoParquet数据集

概述 GeoParquet是一种用于存储地理空间数据的文件格式&#xff0c;基于Apache Parquet。它支持高效地存储和查询大型地理空间数据集&#xff0c;具有良好的压缩性能和**列式**存储结构。GeoParquet还与许多地理信息系统&#xff08;GIS&#xff09;和大数据处理工具兼容&#…

SAP B1 登陆报错解决方案 - 系统架构目录服务器选择

背景 登录时出现如下报错&#xff0c;报错显示为【系统架构目录服务器选择】 强行登录会发现过往账套都不见了 出现原因 出于各种原因在开机时没有把 SAP 所有的服务成功启动&#xff08;上一次启动科学上网后全局代理没关干净之类的&#xff09;。 解决方案 关机几分钟重启…

037集——JoinEntities连接多段线polyline和圆弧arc(CAD—C#二次开发入门)

如图&#xff1a;最终效果 polyline连接&#xff1a; 代码如下&#xff1a; public void joinentities() {Curve pLine Z.db.SelectEntities<Curve>().First().Clone() as Curve;pLine.ChangeEntityColor(1);Curve pLine1 Z.db.SelectEntities<Curve>().First()…

【划分型 DP-约束划分个数】【hard】【阿里笔试】力扣1278. 分割回文串 III

给你一个由小写字母组成的字符串 s&#xff0c;和一个整数 k。 请你按下面的要求分割字符串&#xff1a; 首先&#xff0c;你可以将 s 中的部分字符修改为其他的小写英文字母。 接着&#xff0c;你需要把 s 分割成 k 个非空且不相交的子串&#xff0c;并且每个子串都是回文串…