Map接口用于根据唯一键快速查找值,提供O(1)平均查找性能;HashMap无序且最快,TreeMap按键排序支持范围查询,LinkedHashMap保持插入或访问顺序;computeIfAbsent实现“有则用、无则建”,避免重复创建对象;判断key存在应使用containsKey()而非get()!=null,以防null值歧义。

Map 接口解决“按名字快速找东西”的问题
当你有一堆数据,需要根据一个唯一标识(比如用户 ID、配置项名、缓存 key)直接拿到对应值,而不是遍历查找时,Map 就是为此设计的。它不关心顺序,只保证 key 到 value 的一对一映射和 O(1) 平均查找性能。
HashMap、TreeMap、LinkedHashMap 选哪个?看场景
三者都实现 Map,但底层逻辑不同,直接影响行为:
-
HashMap:无序、允许null键/值、最快(基于哈希表),但遍历时顺序不确定,且线程不安全 -
TreeMap:按键自然排序(或自定义Comparator),支持firstKey()、subMap()等范围操作,但插入/查找是 O(log n) -
LinkedHashMap:保留插入顺序(或访问顺序,启用accessOrder=true时可做 LRU 缓存),性能略低于HashMap,但顺序可预测
例如,做 HTTP 请求头解析,用 LinkedHashMap 能保持 header 写入顺序;做实时排行榜统计,用 TreeMap 可直接取 top N;普通配置缓存,HashMap 最合适。
put() 和 computeIfAbsent() 的关键区别
别一上来就用 put() 覆盖值——很多场景真正需要的是“有则用,无则建”:
立即学习“Java免费学习笔记(深入)”;
-
map.put(key, new ArrayList()):不管 key 是否存在,都新建对象,浪费内存且可能覆盖已有数据 -
map.computeIfAbsent(key, k -> new ArrayList()):只在 key 不存在时才执行 lambda,返回已存在的 value 或新创建的对象,线程安全且惰性初始化
典型用法:
Map> userRoles = new HashMap<>(); userRoles.computeIfAbsent("alice", k -> new ArrayList<>()).add("admin"); userRoles.computeIfAbsent("alice", k -> new ArrayList<>()).add("editor"); // 不会重复 new ArrayList
containsKey() vs get() != null?小心 null 值陷阱
如果 Map 允许 null 值(如 HashMap),仅靠 map.get(key) != null 无法区分“key 不存在”和“key 存在但值为 null”。
- 正确判断 key 是否存在:用
map.containsKey(key) - 想同时获取值并判断是否存在:先
get(),再配合containsKey(),或用getOrDefault(key, sentinel)设默认值 - 如果业务上绝不允许
null值,可在put()前显式校验,避免后续歧义
这个点在从 JSON 或数据库反序列化 Map 时特别容易踩坑——字段缺失和字段显式设为 null 在 Java Map 中表现一样,必须结合上下文或 schema 处理。










