翻车了!在项目中用了Arrays.asList、ArrayList的subList,被公开批评

ArrayList与LinkedList底层原理:从扩容到fail-fast的List面试全解析 在Java集合框架中,List是最基础也最常被问到的数据结构之一。无论是ArrayList的数组扩容机制,还是LinkedList的双向链表结构,背后都涉及内存布局、时间复杂度与工程取舍的深层原理。理解这些底层行为,不仅能解释为什么ArrayList随机访问快而LinkedList插入删除未必更快,还能理解fail-fast机制在迭代遍历中的代价与意义。从数据结构基础到JVM内存模型,再到并发场景下的线程安全选型,List相关技术广泛应用于日常开发、性能优化与大厂面试。掌握扩容因子为何是1.5、subLis 阅读详情
点击上方蓝色“终端研发部”,选择“设为星标”
学最好的别人,做最好的我们

来源:blog.youkuaiyun.com/zwwhnly/article/details/109583990

1. 使用Arrays.asList的注意事项

1.1 可能会踩的坑

先来看下Arrays.asList的使用:

List<Integer> statusList = Arrays.asList(1, 2);
System.out.println(statusList);
System.out.println(statusList.contains(1));
System.out.println(statusList.contains(3));

输出结果如下图所示:

图片

然后,往statusList中添加元素3,如下所示:

statusList.add(3);
System.out.println(statusList.contains(3));

预期的结果,应该是输出true,但是实际却是抛出了java.lang.UnsupportedOperationException异常:

图片

不禁疑问,只是简单添加个元素,为啥会抛这么个异常呢,不科学啊。

1.2 原因分析

带着这个疑问,我们看下Arrays类提供的静态方法asList的源码:

图片

返回的是ArrayList,很熟悉,有木有,但是再细心一看,就会发现此ArrayList并不是我们经常使用的ArrayList,因为我们平时经常使用的ArrayList是位于java.util包下的:

图片

但是此处的ArrayList却是Arrays类的内部类:

它也继承了AbstractList类,重写了很多方法,比如我们上面使用的contains方法,但是却没有重写add方法,所以我们在调用add方法时才会抛出java.lang.UnsupportedOperationException异常。

关于这一点,在《阿里巴巴Java开发手册》泰山版中,也有提及:

“

使用工具类 Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法,它的 add/remove/clear 方法会抛出 UnsupportedOperationException 异常。

”

图片

所以大家在使用Arrays.asList时还是要注意下,避免踩坑。

1.3 总结

Arrays.asList方法可以在一些简单的场合使用,比如快速声明一个集合,判断某个值是否在允许的范围内:

图片

但声明后不要再调用add等方法修改集合,否则会报java.lang.UnsupportedOperationException异常。

2. 使用ArrayList的subList的注意事项

先来看下subList的简单使用:

List<String> bookList = new ArrayList<>();
bookList.add("遥远的救世主");
bookList.add("背叛");
bookList.add("天幕红尘");
bookList.add("人生");
bookList.add("平凡的世界");

List<String> luyaoBookList = bookList.subList(3, 5);

System.out.println(bookList);
System.out.println(luyaoBookList);

运行结果如下图所示:

图片

从运行结果可以看出,subList返回的是bookList中索引从fromIndex(包含)到toIndex(不包含)的元素集合。

使用起来很简单,也很好理解,不过还是有以下几点要注意,否则会造成程序错误或者异常:

  1. 修改原集合元素的值,会影响子集合

  2. 修改原集合的结构,会引起ConcurrentModificationException异常

  3. 修改子集合元素的值,会影响原集合

  4. 修改子集合的结构,会影响原集合

以上几点在《阿里巴巴Java开发手册》泰山版中是这样描述的:

图片

2.1 修改原集合的值,会影响子集合

比如,我们修改下原集合bookList中某一元素的值(非结构性修改 ):

List<String> bookList = new ArrayList<>();
bookList.add("遥远的救世主");
bookList.add("背叛");
bookList.add("天幕红尘");
bookList.add("人生");
bookList.add("平凡的世界");

List<String> luyaoBookList = bookList.subList(3, 5);

System.out.println(bookList);
System.out.println(luyaoBookList);

// 修改原集合的值
bookList.set(3,"路遥-人生");

System.out.println(bookList);
System.out.println(luyaoBookList);

运行结果如下所示:

图片

可以看出,虽然我们只是修改了原集合bookList的值,但是影响到了子集合luyaoBookList。

2.2 修改原集合的结构,会引起ConcurrentModificationException异常

比如,我们往原集合bookList中添加一个元素(结构性修改 ):

List<String> bookList = new ArrayList<>();
bookList.add("遥远的救世主");
bookList.add("背叛");
bookList.add("天幕红尘");
bookList.add("人生");
bookList.add("平凡的世界");

List<String> luyaoBookList = bookList.subList(3, 5);

System.out.println(bookList);
System.out.println(luyaoBookList);

// 往原集合中添加元素
bookList.add("早晨从中午开始");

System.out.println(bookList);
System.out.println(luyaoBookList);
1234567891011121314151617

运行结果如下所示:

图片

可以看出,当我们往原集合中添加了元素(结构性修改)后,在遍历子集合时,发生了ConcurrentModificationException异常。

“

注意事项:以上异常并不是在添加元素时发生的,而是在添加元素后,遍历子集合时发生的。

”

关于这一点,在《阿里巴巴Java开发手册》泰山版中是这样描述的:

图片

2.3 修改子集合的值,会影响原集合

比如,我们修改下子集合luyaoBookList中某一元素的值(非结构性修改 ):

List<String> bookList = new ArrayList<>();
bookList.add("遥远的救世主");
bookList.add("背叛");
bookList.add("天幕红尘");
bookList.add("人生");
bookList.add("平凡的世界");

List<String> luyaoBookList = bookList.subList(3, 5);

System.out.println(bookList);
System.out.println(luyaoBookList);

// 修改子集合的值
luyaoBookList.set(1,"路遥-平凡的世界");

System.out.println(bookList);
System.out.println(luyaoBookList);

运行结果如下所示:

图片

可以看出,虽然我们只是修改了子集合luyaoBookList的值,但是影响到了原集合bookList。

2.4 修改子集合的结构,会影响原集合

比如,我们往子集合luyaoBookList中添加一个元素(结构性修改 ):

List<String> bookList = new ArrayList<>();
bookList.add("遥远的救世主");
bookList.add("背叛");
bookList.add("天幕红尘");
bookList.add("人生");
bookList.add("平凡的世界");

List<String> luyaoBookList = bookList.subList(3, 5);

System.out.println(bookList);
System.out.println(luyaoBookList);

// 往子集合中添加元素
luyaoBookList.add("早晨从中午开始");

System.out.println(bookList);
System.out.println(luyaoBookList);

运行结果如下所示:

图片

可以看出,当我们往子集合中添加了元素(结构性修改)后,影响到了原集合bookList。

2.5 原因分析

首先,我们看下subList方法的注释,了解下它的用途:

图片

“

Returns a view of the portion of this list between the specified {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.

”

翻译过来意思就是:

“

返回指定的{@code fromIndex}(包含)和{@code toIndex}(排除)之间的列表部分的视图。

”

然后,我们看下它的源码:

public List<E> subList(int fromIndex, int toIndex) {
    subListRangeCheck(fromIndex, toIndex, size);
    return new SubList(this, 0, fromIndex, toIndex);
}

可以看到,它调用了SubList类的构造函数,该构造函数的源码如下图所示:

图片

可以看出,SubList类是ArrayList的内部类,该构造函数中也并没有重新创建一个新的ArrayList,所以修改原集合或者子集合的元素的值,是会相互影响的。

2.6 总结

ArrayList的subList方法,返回的是原集合的一个子集合(视图),非结构性修改任意一个集合的元素的值,都会彼此影响,结构性修改原集合时,会报ConcurrentModificationException异常,结构性修改子集合时,会影响原集合,所以使用时要注意,避免程序错误或者异常。

3. 画外音

大家在定义方法的时候,如果返回值类型是 List 的话,一定要去思考是否允许修改 !

如果不允许,在方法的注释上,一定要说明清楚这个事儿。

很多时候,我们是为了方便的创建一个 List,而不是想手动去一个一个去 add 元素,那么此时可以掏出 Guava 提供的如下几个:

Lists.newArrayList(E... elements)

Sets.newHashSet(E... elements)

不得不说,Guava,yyds(永远滴神)!!!

BAT等大厂Java面试经验总结 想获取 Java大厂面试题学习资料扫下方二维码回复「BAT」就好了回复 【加群】获取github掘金交流群回复 【电子书】获取2020电子书教程回复 【C】获取全套C语言学习知识手册回复 【Java】获取java相关的视频教程和资料回复 【爬虫】获取SpringCloud相关多的学习资料回复 【Python】即可获得Python基础到进阶的学习教程回复 【idea破解】即可获得intellij idea相关的破解教程回复 【BAT】即可获得intellij idea相关的破解教程关注我gitHub掘金,每天发掘一篇好项目,学习技术不迷路!


回复 【idea激活】即可获得idea的激活方式

回复 【Java】获取java相关的视频教程和资料

回复 【SpringCloud】获取SpringCloud相关多的学习资料

回复 【python】获取全套0基础Python知识手册

回复 【2020】获取2020java相关面试题教程

回复 【加群】即可加入终端研发部相关的技术交流群

阅读更多

为什么HTTPS是安全的

因为BitMap,白白搭进去8台服务器...

《某厂内部SQL大全 》.PDF

字节跳动一面:i++ 是线程安全的吗?

大家好,欢迎加我微信,很高兴认识你!

在华为鸿蒙 OS 上尝鲜,我的第一个“hello world”,起飞!

相信自己,没有做不到的,只有想不到的

在这里获得的不仅仅是技术!


喜欢就给个“在看”

matlab 点云泊松盘采样 本文介绍了泊松盘采样算法在三维点云处理中的应用。该算法通过最小间距约束(任意两点距离≥r)和均匀分布特性,生成高质量、均匀分布的点集。文章详细阐述了参数设置(如采样半径、候选点数),并与体素栅格、随机采样等方法进行了对比。代码实现部分展示了MATLAB版本的泊松盘采样算法,包括KD树加速和候选点生成机制。实验结果表明,该方法能有效保持点云特征,适用于点云简化、曲面重建等场景。文中还提供了参数调整建议和不同应用场景下的使用指导。 阅读详情

相关推荐

告别CPU空转!用STC8的SPI+DMA高效驱动上百颗WS2812B灯珠

本文详细解析了如何利用STC8单片机的SPI+DMA外设高效驱动WS2812B全彩灯珠,解决传统软件延时驱动方式在长灯带应用中的性能瓶颈。通过硬件方案设计、数据格式转换和DMA传输配置,实现高达400Hz的刷新率和低于5%的CPU占用率,适用于大规模灯光项目。

weixin_30847939的博客 396

Java——书单列表BookList

Description 构建一个书单类BookList,该类中用一个列表类对象存放书单,提供添加图书(addBook)、查找图书(searchBook)的函数 main函数从键盘输入多个Book添加到书单中,(添加时,提供书的名称、价格、作者、版本号),而后从键盘读入一本书,查找该列表对象中是否包含该书,若包含,输出”found: 该书在列表中的序号”,若不包含,输出“not found”,查...

Yolanda_Vamper的博客 4285

STM32G474串口调试避坑指南:从CubeMX配置到中断收发,手把手教你搞定USART1

本文详细解析了STM32G474串口调试中的常见问题,从CubeMX配置到中断收发,提供USART1的避坑指南。涵盖时钟树同步、GPIO模式选择、中断接收逻辑、波特率偏差修正等关键点,帮助开发者高效解决串口通讯难题,提升嵌入式开发效率。

weixin_29191081的博客 210

Redis反序列化错误Could not read JSON: Cannot construct instance of `java.util.ArrayList$SubList`

最近使用Redis做缓存,用着好好的,返现有一个方法的在从Redis获取缓存时报错,无法正常获取到缓存,从报错信息看,是不能发序列化。在这里记录一下解决方法。

A1682234的博客 706

GK2302量产工具下载方法,GK2302开卡教程,GK2301LT怎么开卡方法,附GK2302开卡工具,GK2301LT量产软件下载

​每种量产软件的操作流程可能略有不同,因此必须按照要求操作。为确保安全,建议使用量产部落网下载的原版量产开卡软件。

A520091000的博客 2123

全网最详细Seurat v5 流程复现(拿来即用)

本文是基于seurat v5版本的教程复现,主要依据来源于官网seurat v5建议大家有时间的话可以去官网进行详细阅读学习!本节内容在之前seurat v4的教程都很多都有提到,文章所用到的数据及代码已经给各位放在这里了,有需要自取!请点击这里哦提取码:bui1。

ZxVSaccount的博客 1万+

揭秘Arrays.asList的线程安全之谜与线程安全Set的三重奏

通过本文的探讨,我们不仅揭开了的线程安全之谜,还学习了如何实现线程安全的替代方案。同时,我们还了解了三种线程安全的Set实现。这些知识对于每一个Java高级架构师来说都是宝贵的财富。希望本文能够帮助你在多线程编程的道路上更进一步。你的每一次互动都是对我最大的支持。让我们一起在Java的世界中不断探索和成长!🚀。

赵KK的博客 1385

1.3-----Simplify 3D切片软件:从新手困惑到高效打印的进阶设置指南

本文详细介绍了Simplify 3D切片软件在大型模型打印中的高效设置技巧,包括切片效率、支撑结构智能生成和精细参数调节等核心优势。通过实战案例和进阶参数设置指南,帮助用户从新手快速进阶到高效打印,显著提升3D打印质量和效率。

weixin_42552716的博客 422

常用线程安全类型(ArrayList、LinkedList、CopyOnWriteArrayList、HashMap、LinkedHashMap、ConcurrentHashMap)

常用线程安全类型(ArrayList、LinkedList、CopyOnWriteArrayList、HashMap、LinkedHashMap、ConcurrentHashMap)、线程安全

YimBa的博客 5718

行为预测模型:Social LSTM与Graph Neural Networks

行为预测模型:Social LSTM与Graph Neural Networks ,人工智能,计算机视觉,大模型,AI,本文围绕行为预测模型Social LSTM与Graph Neural Networks展开,介绍了两者的基础概念、原理、应用场景,还对比了它们在优势、劣势和适用场景上的不同,最后给出了相应的代码示例。Social LSTM基于LSTM,通过社交池化层处理多智能体交互;图神经网络处理图结构数据,靠消息传递获取信息,二者各有侧重,适用于不同场景。

不踩坑,不知道坑有多深;不总结,踩过的坑白踩。 15万+

基于 STM32 的智能水表流量计设计与实现 —— 数据采集与远程传输

本文设计的基于 STM32 的智能水表流量计通过霍尔传感器实现流量采集,结合 STM32 的处理能力完成数据计算、存储与远程传输,具备计量精准、功耗低、可远程监控等特点。未来可优化方向:引入低功耗模式延长电池寿命,增加水质检测模块实现多参数监测,提升水务管理智能化水平。

weixin_42300449的博客 1028

翻车!在项目中用了Arrays.asList、ArrayList的subList,被公开批评

往期热门文章:1、想接私活时薪再翻一倍,建议根据这几个开源的Spring Boot项目改改~2、细数ThreadLocal三大坑,内存泄露仅是小儿科3、Redis与MySQL双写一致性如何...

Java后端技术 378

GPFS扩展技术原理(十一)-FMDN广播与EID加解密

GFPS扩展技术原理(十一)FMDN广播及EID加解密

十多年蓝牙协议软件开发,擅长蓝牙协议分析 935

完蛋!项目中用了Arrays.asList、ArrayList的subList,翻车了

方法可以在一些简单的场合使用,比如快速声明一个集合,判断某个值是否在允许的范围内:但声明后不要再调用add等方法修改集合,否则会报异常。ArrayList的subList方法,返回的是原集合的一个子集合(视图),非结构性修改任意一个集合的元素的值,都会彼此影响,结构性修改原集合时,会报异常,结构性修改子集合时,会影响原集合,所以使用时要注意,避免程序错误或者异常。

2501_92606851的博客 430

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

别再背八股:ArrayList与LinkedList源码级剖析与实战避坑指南

Java集合框架中的List接口是日常开发最常用的数据结构之一,而ArrayList与LinkedList的底层实现差异、扩容机制以及迭代器行为,直接影响着系统性能与稳定性。理解数组连续内存与链表节点分散的内存模型,能解释为何随机访问、增删操作的真实复杂度与直觉不同。ArrayList基于动态数组,通过grow()实现1.5倍扩容;LinkedList基于双向链表,在持有节点引用时才具备O(1)插入优势。同时,modCount与fail-fast机制保证了遍历时对并发修改的快速失败,而CopyOnWrite

weixin_34075268的博客 440

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Java集合类面试全解析:从ArrayList到HashMap

Java集合类是面试中的高频考点,涉及数据结构、算法复杂度、线程安全等核心概念。ArrayList基于动态数组实现,支持快速随机访问;LinkedList采用双向链表结构,适合频繁插入删除。两者在时间复杂度、内存布局和CPU缓存命中率上存在显著差异。HashMap作为关键数据结构,其负载因子、扩容机制和红黑树转换策略直接影响系统性能。在并发场景下,ConcurrentHashMap通过分段锁保证线程安全。理解这些集合类的底层原理,能帮助开发者在电商商品列表、缓存系统等实际场景中做出合理选择,提升代码执行效率

weixin_34236869的博客 315
上一篇: 从Windows到Bios的桥梁:Windbg跟踪Win7开启ACPI
下一篇: Nginx超详细入门!
androidstarjack
博客等级 码龄12年 3277粉丝 697原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值