Java集合遍历3大死亡陷阱!90%新手都中招(附逃生代码)

Java集合遍历3大死亡陷阱!90%新手都中招(附逃生代码)

编码文章call10242025-05-30 11:19:3914A+A-

导语:

“你的程序突然抛出
ConcurrentModificationException?不是见鬼,是Java集合遍历的‘死亡陷阱’在索命!今日头条揭秘电商系统崩溃背后的集合操作黑幕,阿里P7急救代码曝光,文末送《集合安全手册》+调试工具包!”


一、死亡循环:foreach删除引发的血案

用户求救
“遍历List删除元素时程序崩溃,日志显示神秘异常!”

致命代码

List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));  
for (String s : list) {  
    if ("B".equals(s)) {  
        list.remove(s);  // 抛出ConcurrentModificationException!  
    }  
}  

逃生方案

// 正确方式1:迭代器删除  
Iterator<String> it = list.iterator();  
while (it.hasNext()) {  
    if ("B".equals(it.next())) {  
        it.remove(); // 安全删除  
    }  
}  

// 正确方式2:removeIf一行搞定  
list.removeIf(s -> "B".equals(s));  

二、性能刺客:嵌套循环毁掉CPU

灾难场景

List<User> users = get10万用户();  
List<Order> orders = get100万订单();  

// 双重循环:时间复杂度O(n^2)  
for (User user : users) {  
    for (Order order : orders) {  
        if (order.getUserId().equals(user.getId())) {  
            // 业务处理  
        }  
    }  
}  

后果

  • 10万用户 × 100万订单 = 1000亿次比较
  • CPU占用100%持续2小时 → 服务器熔断

优化代码

Map<String, List<Order>> orderMap = orders.stream()  
    .collect(Collectors.groupingBy(Order::getUserId));  

for (User user : users) {  
    List<Order> userOrders = orderMap.getOrDefault(user.getId(), emptyList());  
    // 时间复杂度降为O(n)  
}  

三、内存黑洞:未设初始容量的ArrayList

错误示范

List<byte[]> list = new ArrayList<>(); // 默认容量10  
for (int i=0; i<100_000; i++) {  
    list.add(new byte[1024]); // 触发15次扩容复制!  
}  

扩容代价

操作次数

扩容后容量

拷贝数据量

1

10 → 15

10KB

10

15 → 22

15KB

15

22 → 33

22KB

总计:100万元素扩容18次 → 拷贝数据量超1GB



正确代码

List<byte[]> list = new ArrayList<>(100_000); // 预分配容量  

四、福利时间

“私信发送‘集合’免费领

  1. 《Java集合框架源码解析》
  2. 高频面试题答案库(含大厂真题)
  3. 阿里内部《性能压测报告模板》

下期预告
《Java并发编程:从ThreadLocal内存泄漏到百万QPS架构设计!》点击关注,进阶架构师!

点击这里复制本文地址 以上内容由文彬编程网整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!
qrcode

文彬编程网 © All Rights Reserved.  蜀ICP备2024111239号-4