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

相关推荐
松仔log29 分钟前
JetPack——Paging3+Room
android·java·zoom
㳺三才人子6 小时前
初探 Flask
后端·python·flask·html
星栈独行6 小时前
我在 Rust 全栈项目里用 JWT 做无状态认证
开发语言·后端·rust·前端框架·开源·github·web
Lei活在当下6 小时前
先用起来,再理解,关于协程Coroutine应该知道的事
android·java·jvm
Java爱好狂.6 小时前
Java程序员体系化学习路线(2026最新版)
java·后端·java面试·java架构师·java程序员·java八股文·java学习路线
陈随易6 小时前
Redis 8.8发布,一定要更新
前端·后端·程序员
tongluowan0076 小时前
以ReentrantLock为例解释AQS的工作流程
java·模板方法模式·aqs·reentrantlock
装不满的克莱因瓶7 小时前
SpringBoot 如何将 lib 目录中jar包打包进最终的jar包里面
spring boot·后端·maven·jar·mvn
ltl7 小时前
Transformer 原论文实验结果:为什么 28.4 BLEU 足以改写路线图
后端
身如柳絮随风扬8 小时前
Java 项目打包与部署完全指南:JAR vs WAR,从构建到运行
java·firefox·jar