大家好,我是剽悍一小兔,独立开发者,副业搞钱尝试者,热爱技术分享。曾经当过培训机构老师,也带过大学H5编程实训课,目前还活跃在金融领域一线做全栈开发。
我会每天分享 编程技术、独立开发、思考感悟。
代表作:《JavaScript百炼成仙》
公众号:java小白翻身
如果本文能给你提供启发或帮助,欢迎动动小手指,一键三连 (点赞
、评论
、转发
),给我一些支持和鼓励,谢谢。
各位程序员朋友们,今天咱们来聊聊我最近在项目里踩的两个大坑——Arrays.asList和ArrayList.subList,这俩“坑王”可把我坑惨了,被老大当众点名批评!当时我脑子一片空白,甚至怀疑自己是不是个合格的Java工程师。不过冷静下来复盘后,我发现这俩API确实暗藏玄机,今天就来给大家好好唠唠,避免大家踩同样的坑!
一、Arrays.asList:披着羊皮的狼!
先说说第一个“坑王”——Arrays.asList。那天我在项目里需要判断一批状态码,为了代码看起来清爽,我直接写了:
List<Integer> statusList = Arrays.asList(1, 2);
statusList.add(3);
结果IDE控制台直接炸出UnsupportedOperationException
!我当时就懵了:这不是ArrayList吗?咋不能加元素呢?
划重点! Arrays.asList返回的根本不是我们熟悉的java.util.ArrayList
,而是Arrays$ArrayList
——这是Arrays的内部类,底层是固定长度的数组,只支持查询和修改,不支持增删操作!
正确用法:如果需要可变集合,一定要手动转换:
List<Integer> realList = new ArrayList<>(Arrays.asList(1, 2));
realList.add(3); // 这样才对!
Arrays.asList适合干啥?做个快速初始化、判断包含关系就行,比如:
if (Arrays.asList(1, 2, 3).contains(userInput)) { ... }
别想着用它搞增删,否则就是“强行上车,后果自负”!
二、subList:表面兄弟,实则共享内存!
第二个“坑王”是ArrayList.subList。我当时需要处理书籍列表的某部分数据,写了:
List<String> bookList = new ArrayList<>(Arrays.asList("遥远的救世主", "背叛", "天幕红尘", "人生", "平凡的世界"));
List<String> luyaoBooks = bookList.subList(3, 5); // 得到["人生", "平凡的世界"]
结果一操作,直接踩中四颗“地雷”:
第一雷:改原集合,子集合跟着变!
bookList.set(3, "路遥-人生");
System.out.println(luyaoBooks); // 输出["路遥-人生", "平凡的世界"]
为啥?因为subList返回的是原集合的视图,两者共用同一个底层数组,改一个另一个必然跟着变,就像照镜子,你动镜子里的人也动!
第二雷:原集合增元素,子集合遍历爆炸!
bookList.add("早晨从中午开始");
luyaoBooks.get(0); // 抛出ConcurrentModificationException!
这不是线程问题,而是subList依赖原集合的modCount
(修改次数),原集合结构一变(增/删),modCount
对不上,直接炸!
第三雷:改子集合,原集合也变!
luyaoBooks.set(1, "路遥-平凡的世界");
System.out.println(bookList.get(4)); // 输出"路遥-平凡的世界"
还是视图的锅,改子集合相当于改原集合,根本没有独立性!
第四雷:子集合增元素,原集合背锅!
luyaoBooks.add("人生的枷锁");
System.out.println(bookList); // 原集合多了个元素!
结构修改在子集合做,原集合照样受牵连,谁让你们共用一个“身体”呢?
避坑指南:如果需要独立子集合,记得拷贝一份:
List<String> realSubList = new ArrayList<>(bookList.subList(3, 5));
这样两者就“断奶”了,互不影响!
三、血泪教训:别对API想当然!
这次被老大批评,我总结了三个教训:
-
1. Arrays.asList不是真ArrayList,名字都是骗人的,增删操作请用
new ArrayList<>(...)
转换! -
2. subList是视图不是拷贝,改结构会互相影响,独立操作请先拷贝!
-
3. 别迷信IDE自动补全!List不等于ArrayList,ArrayList也分“真假”,用之前先搞清楚底层原理!
老大最后拍着我的肩膀说:“代码里没有‘看起来可以’,只有‘实际行不行’。”这句话我记牢了!多踩坑,多涨记性,这才是程序员的成长之路!