跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

Java集合框架中的Set与Map的应用场景

该用Set而非List当需自动去重且不关心顺序或索引;HashSet平均O(1)、LinkedHashSet保插入序、TreeSet支持排序但O(log n),注意null限制。 什么时候该用
Set
而不是
List
当你需要自动去重、且不关心元素顺序或索引访问时,
Set
是更合适的选择。比如读取一批用户 ID 并统计唯一数量,用
List
后手动去重不仅慢(
O(n²)
),还容易漏掉边界情况。
HashSet
最常用:底层是哈希表,插入/查找平均
O(1)
,但不保证顺序
LinkedHashSet
适合需要按插入顺序遍历的场景,比如最近访问的资源缓存
TreeSet
用于需要自然排序或自定义排序的集合,比如排行榜分数去重后升序展示,但增删查是
O(log n)
注意:
Set
不能存
null
(
TreeSet
直接抛
NullPointerException
;
HashSet
允许一个
null
,但要小心后续比较逻辑)
Map
的键为什么必须是不可变对象 因为
Map
(尤其是
HashMap
)依赖键的
hashCode()
和
equals()
定位和比较元素。如果键对象在放入后被修改,导致
hashCode()
变化,就再也找不到它了——不是丢失,是“藏起来了”。 常见踩坑:用可变的
StringBuilder
或自定义类作键,没重写
hashCode()
和
equals()
,或重写了但字段参与计算后又被改 安全做法:优先用
String
、
Integer
等不可变类型;若必须用自定义类,确保所有参与
hashCode()
/
equals()
的字段在构造后不可变 例如:
Map userScore = new HashMap<>(); userScore.put("alice", 95); // 后续用 "alice" 能稳定取到,因为 String 不可变
Set
和
Map
在实际业务中怎么配合用 很多场景下二者不是二选一,而是协同:用
Map
存主数据 + 关联关系,用
Set
做快速存在性判断或去重中间结果。 立即学习 “ Java免费学习笔记(深入) ”; Eclipse导入Android或其他的JAVA项目的正确方法 WORD版 本文档主要讲述的是Eclipse导入Android或其他的JAVA项目的正确方法;希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看 下载 权限校验:把用户拥有的角色 ID 存进
HashSet
,检查是否包含某个角色时用
roles.contains("ADMIN")
,比遍历
List
快得多 批量更新防重:从消息队列收到一批订单 ID,先塞进
Set
去重,再查
Map
批量加载已有订单,避免重复 DB 查询 配置白名单:把合法的 API 路径存在
Set
,拦截器里直接判断
if (!allowedPaths.contains(path)) reject();
性能关键点:别为了“看起来统一”而强行把
Map
当
Set
用——语义不清,内存浪费,还可能因
null
值引发误判。 并发环境下选哪个实现 单线程用
HashSet
/
HashMap
没问题,但多线程写入必须换线程安全版本,否则会出错或死循环(JDK 7 的
HashMap
扩容时可能形成环形链表)。 简单读多写少:用
Collections.synchronizedSet()
/
synchronizedMap()
,但锁粒度大,吞吐低 高并发读写:优先选
ConcurrentHashMap
;它没有
ConcurrentHashSet
,但可用
ConcurrentHashMap.newKeySet()
(JDK 8+)替代 注意:
ConcurrentHashMap
的
size()
不是精确值(为避免锁竞争而妥协),需精确计数建议用
LongAdder
单独维护 最容易被忽略的是:即使用了
ConcurrentHashMap
,复合操作如“检查不存在再 put”仍需
computeIfAbsent()
或
putIfAbsent()
,否则仍有竞态。

相关文章