别再乱 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个真实场景让你代码更优雅》

相关推荐
子兮曰3 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
小羊没烦恼!3 天前
微服务化的基石——持续集成
java·大数据·word·powerpoint·.net
子兮曰3 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
俊昭喜喜里3 天前
java中的继承和多态的区别
java
小羊没烦恼!3 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
爱勇宝3 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
譕痕3 天前
JSONObject与JSONArray封装数据格式区别
java·json
胡写代码3 天前
别再前后端各写一套表单校验了
java·后端
小鱼能吃糖3 天前
缺陷修复总览 · mall电商项目:5类缺陷,1个病根,4个业务域
java·电商
此时不提桶,更待何时3 天前
01-06-A-JVM排查实战详解
java·jvm