别再乱 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); // 大部分是读操作
}
// 后面全是遍历展示,不增不删

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

所以,要是频繁插入删除的操作,别用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 官方都推荐用它替代StackLinkedList做栈或队列。

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

总结一下

需求 推荐用
普通列表,读多写少 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个真实场景让你代码更优雅》

相关推荐
C++、Java和Python的菜鸟4 分钟前
第4章 后端Web基础(基础知识)
java·开发语言
芷栀夏12 分钟前
Java教育平台实战复盘:课程、考试与学习行为分析系统设计
java·开发语言·学习
从零开始的代码生活_19 分钟前
C++ 多态详解:虚函数、动态绑定、抽象类与虚表原理
开发语言·c++·后端·学习·算法
神奇小汤圆27 分钟前
吃透MySQL核心原理:日志、事务、MVCC、锁机制深度详解
后端
老孙讲技术31 分钟前
零售后端笔记:AI 能力接不上?先分清 numberstat / alarm / faceAnalysis 三条管
后端·物联网
维基框架37 分钟前
维基框架(Wiki-Framework) 1.2.0:Mybatis 升级为主从读写分离
java·后端·架构
Memory_荒年40 分钟前
Java函数式接口:把代码变成“拼乐高”的快乐,你体验过吗?
java
Memory_荒年1 小时前
WebSocket:让服务器学会“主动搭讪”的黑科技
java
Larcher1 小时前
MCP协议实战:让AI Agent跨进程调用工具的正确姿势
人工智能·后端