别再乱 new ArrayList!8 大 Java 容器选型案例,一篇看懂

你是不是也这样过?写代码,一上来就是:

java 复制代码
List<String> list = new ArrayList<>();

管它三七二十一,先new一个ArrayList再说!

我以前也是这样。直到有一次,线上接口慢得像蜗牛,排查半天,发现是某个地方用了ArrayList存了几万条数据,还频繁删除插入......直接卡崩了。

容器用错了,性能能差十倍不止。

下面记录一下。

1. ArrayList:适合读多写少

你从数据库拉了一堆用户列表,展示用,基本不改。

这种情况,ArrayList是首选。

java 复制代码
List<User> users = userService.getAllUsers();
for (User u : users) {
    render(u); // 大部分是读操作
}
// 后面全是遍历展示,不增不删

它的优点是按位置访问快。你要是在中间insert或remove ,它就得把后面的元素全往后挪,特别耗时。

所以,要是频繁插入删除的操作,别用ArrayList。

2. LinkedList:适合链式操作的场景

有次我们做后台管理,要支持"撤销上一步"功能。

比如用户连续改了 5 次标题,点撤销,就得一步步退回去。

最开始用ArrayList存操作记录:

java 复制代码
List<EditAction> history = new ArrayList<>();

每次撤销,都要remove最后一条。结果数据一多,删除慢得不行,界面卡顿。

后来换成LinkedList:

java 复制代码
LinkedList<EditAction> history = new LinkedList<>();

因为是链表结构,删最后一个节点,O(1) 就搞定。

而且我们还用它当栈使用:

scss 复制代码
history.addLast(action);  // 入栈
history.removeLast();     // 出栈,撤销

LinkedList的头尾操作天生就快,指针一指,完事。

3. HashMap:日常键值存储

用户登录后,把基本信息缓存在内存里。

java 复制代码
Map<Long, User> userMap = new HashMap<>();
userMap.put(user.getId(), user);
User target = userMap.get(10086L);

查得快,写得也快,日常开发用得最多。

但注意,它不保证顺序,也不支持并发。

4. LinkedHashMap:要顺序,就它了

有时候你希望Map的遍历顺序和插入顺序一致。

比如记录用户操作日志,按时间顺序存。

java 复制代码
Map<String, Action> log = new LinkedHashMap<>();
log.put("login", loginAction);
log.put("pay", payAction);
// 遍历时,先 login,后 pay

遍历时,最近访问的在前面。

而且插入顺序固定,前端展示不乱。

5. TreeMap:需要自动排序

你要按分数给学生排名,key是分数。

用TreeMap,它自动按key排好。

java 复制代码
Map<Integer, String> rank = new TreeMap<>();
rank.put(95, "张三");
rank.put(88, "李四");
// 遍历出来就是按分数从小到大

遍历出来就是有序的。

虽然比HashMap慢点,但省了你手动排序的麻烦。


6. ConcurrentHashMap:并发写 Map,就它了

多个线程同时往缓存里put数据。

java 复制代码
Map<String, Object> cache = new ConcurrentHashMap<>();
cache.put("token_123", token);
Object obj = cache.get("token_123");

线程安全,性能好,高并发场景下Map的唯一选择。

别用Collections.synchronizedMap,太慢。

7. CopyOnWriteArrayList:读多写少的并发 List

系统里有一堆短信发送监听器。

大部分时间都在遍历通知:

java 复制代码
List<EventListener> listeners = new CopyOnWriteArrayList<>();
for (EventListener l : listeners) {
    l.onSend(sms);
}
// 遍历通知时完全无锁,特别快
// 写操作会复制数组,所以写不能太频繁

它的读操作不加锁,性能极高。

但每次写都要复制整个数组,写多的话,内存和 CPU 都扛不住。

所以,写得少,读得多,才考虑它。

8. ArrayDeque:队列和栈,首选它

实现一个任务队列,或者当栈用。

java 复制代码
Deque<Task> tasks = new ArrayDeque<>();
tasks.addLast(newTask); // 入队
Task t = tasks.removeFirst(); // 出队

它底层是数组,比LinkedList内存更加紧凑,操作更快。

Java 官方都推荐用它替代Stack和LinkedList做栈或队列。

除非你要中间插入,否则优先选它。

总结一下

需求 推荐用
普通列表,读多写少 ArrayList
头尾增删频繁 ArrayDeque
键值对,快 HashMap
要保持插入顺序 LinkedHashMap
key 需要排序 TreeMap
多线程写 Map ConcurrentHashMap
多线程读多写少 List CopyOnWriteArrayList
队列或栈 ArrayDeque

容器不是随便选的。

用对了,程序跑得稳;用错了,半夜叫你修 bug。

我是大华,关注我,少走弯路,一起进步! 觉得有用的话,点个爱心,让更多人看到吧!

📌往期精彩

《Elasticsearch 太重?来看看这个轻量级的替代品 Manticore Search》 《别再if套if了!Java中return的9种优雅写法》 《别学23种了!Java项目中最常用的6个设计模式,附案例》 《Vue3+TS设计模式:5个真实场景让你代码更优雅》

相关推荐
瑞克-桑切斯12 分钟前
7、MySQL 慢查询排查与优化实战指南
java·服务器·数据库
考虑考虑1 小时前
Posrgresql恢复.backup文件
数据库·后端·postgresql
无奈何杨2 小时前
风控决策系统决策流,策略模式,权重、顺序、投票、最坏
后端
Patrick_Wilson3 小时前
Go 为什么需要 defer?从函数怎么收尾说起
后端·go·编程语言
苏三说技术3 小时前
DeepSeek Harness入驻B站,评论区被干成了大型插件集市!
后端
橙序员小站3 小时前
我一句话让 AI 把公众号工作台搭完了:部署实测记录
后端
Patrick_Wilson3 小时前
从文本输出理解 Go 方法与接口
后端·go·编程语言
QCoding4 小时前
企业级Agent Evaluation实战:Agent能跑就能上线?AI Agent到底怎么测?
后端·spring
苍何4 小时前
让 WorkBuddy 操控浏览器,干活有点猛啊1
后端
海的透彻5 小时前
dockerfile如何快速构建容器(java服务)
java·开发语言