是的,但仅限于“结构不可变”——不能增删改元素或调用clear()/put();若元素本身可变(如arraylist),其内部状态仍可被修改。

Java 14+ 的 List.of 和 Map.of 真的不可变吗?
是的,但仅限于“结构不可变”——不能增删改元素,也不能调用 clear() 或 put();但若元素本身可变(比如 ArrayList 实例),其内部状态仍可能被修改。这是最容易误判的一点。
常见错误现象:UnsupportedOperationException 在调用 add()、set()、remove() 时抛出;但若你拿到一个 List.of(new ArrayList()),再对里面那个 ArrayList 调用 add(),代码能跑通,集合内容却悄悄变了。
-
List.of()返回的是私有静态内部类(如ImmutableCollections.ListN),重写了所有修改方法并直接 throw -
Map.of()对 key 和 value 都不做深拷贝,只保证容器结构不可变 - 空集合用
List.of()和Map.of()安全,但含 null 元素会立即抛NullPointerException
什么时候该用 List.of,而不是 Arrays.asList?
Arrays.asList 返回的是“固定大小但可变”的列表——支持 set()、get(),甚至能通过 toArray() 后再转成可变集合;而 List.of 是真·不可变,连 set() 都不给碰。
使用场景:配置项枚举、HTTP 状态码映射表、测试用的只读数据集。如果你需要“初始化后就锁死”,选 List.of;如果还要在后续逻辑里改几个值,别硬套它,否则 runtime 直接崩。
-
Arrays.asList("a", "b")支持list.set(0, "x"),List.of("a", "b")调用会抛异常 -
Arrays.asList底层是数组包装,List.of是独立实现,后者序列化更轻量、线程安全更强 - 注意兼容性:
List.of是 Java 9 引入,但只有 Java 14+ 才支持超过 10 个参数的重载(List.of(a,b,c...)最多支持 12 个)
Map.of 的 key 必须满足什么条件?
key 必须是不可变且正确实现 equals() 和 hashCode() 的类型,否则运行时行为不可靠——不是编译报错,而是查不到、重复插入、甚至 containsKey() 返回 false。
典型翻车现场:用自定义对象当 key,没重写 equals/hashCode;或者用了 new String("abc") 但字符串池未生效,导致两个语义相同但引用不同的 key 被当成不同键。
-
Map.of("k1", "v1", "k2", "v2")没问题,因为String是不可变且重写了哈希方法 - 用
new Date()当 key?危险——Date可变,且hashCode()基于毫秒数,之后改时间会导致 map 查找失效 - 用
StringBuilder?不行,它没重写hashCode(),默认用对象地址,每次 new 都算新 key
性能和内存开销:为什么小集合优先用 List.of/Map.of?
它们比 new ArrayList() + add() 组合更省 GC 压力——没有中间临时对象,不触发扩容,也不做防御性拷贝。尤其在高频创建短生命周期集合的场景(比如 HTTP 请求解析、日志上下文构建),差异明显。
但注意边界:超过 12 个元素必须用 List.ofEntries 或 Map.ofEntries(Java 9+),否则编译失败;而 Map.ofEntries(Map.entry(k1,v1), Map.entry(k2,v2)) 写法稍啰嗦,容易漏括号。
-
List.of(1,2,3)直接返回单例或紧凑数组,new ArrayList(Arrays.asList(1,2,3))至少创建 3 个对象 -
Map.of不接受重复 key,重复会编译时报错(不是运行时),这点比HashMap更早暴露问题 - 调试时注意:IDE 可能无法展开
List.of的内部结构,显示为ImmutableCollections$ListN,别误以为是空或损坏
真正麻烦的不是语法,是把“不可变”当成“元素不可变”。哪怕用对了 List.of,只要里面塞了个可变对象,整个不可变契约就垮了。










