什么是不可变集合?List.of与Map.of的使用方法详解

来源:站长论坛作者:比特币程序员头衔:程序员
导读:本期聚焦于小伙伴创作的《什么是不可变集合?List.of与Map.of的使用方法详解》,敬请观看详情。把集合声明为不可变后,任何新增、删除或修改元素的操作都会直接抛出异常,从语言层面杜绝了意外的数据篡改。Java 9 引入的 List.of 与 Map.of 工厂方法,用极简语法创建出天然不可变的对象,既轻量又线程安全。和传统 Collections.unmodifiableList 不同,of 系列返回的是真正拒绝修改的实例,而非包裹可变对象的视图。在多线程共享配置、方法返回防御性副本等场景中,优先使用 of 方法能减少样板代码,也避免运行时才暴露修改异常的隐患。理解其底层实现与限制,有助于写出更稳健的 Java 代码。

不可变集合是指创建之后内容固定、结构不可更改的集合对象。在 Java 9 之前,开发者通常借助 Collections.unmodifiableList 等工具方法把可变集合包装成只读视图,但从 Java 9 开始,JDK 直接在 List、Set、Map 接口上提供了 of 静态工厂方法,能够一行代码生成真正的不可变集合。这类集合在并发读取、配置传递、返回值保护等场景中非常实用。

什么是不可变集合?List.of与Map.of的使用方法详解

不可变集合的核心特征

不可变集合最重要的特点是创建后不支持任何修改操作。无论是调用 add、remove、put 还是 replace,都会抛出 UnsupportedOperationException。这与线程安全并不完全相同,但不可变对象由于状态不变,天然可以被多个线程同时读取而无需加锁。

另一个容易被忽略的点是,of 方法返回的集合本身并不允许传入 null 元素。以 List.of 为例,如果尝试放入 null,会在构建阶段直接抛出 NullPointerException,从而尽早暴露问题。相比之下,早期通过 unmodifiableList 包装的集合,底层仍可能是含 null 的可变列表,只是外层禁止修改。

List.of 的基本用法

List.of 提供了一组重载方法,支持零到十个元素直接传参,也支持接收数组或可变参数。下面的示例展示了如何创建不可变列表,并演示修改时会得到的异常。

import java.util.List;

public class ImmutableListDemo {
    public static void main(String[] args) {
        // 创建包含三个元素的不可变列表
        List<String> names = List.of("Alice", "Bob", "Charlie");

        System.out.println(names); // 输出 [Alice, Bob, Charlie]

        // 以下操作会在运行时抛出异常
        try {
            names.add("David");
        } catch (UnsupportedOperationException e) {
            System.out.println("不能添加元素: " + e);
        }

        // 也不能通过 set 修改
        try {
            names.set(0, "Eve");
        } catch (UnsupportedOperationException e) {
            System.out.println("不能修改元素: " + e);
        }
    }
}

从代码可以看出,List.of 的返回对象属于 JDK 内部实现的不可变列表类型,例如 ImmutableCollections.ListN。它不持有对外部数组的引用,传入的元素会被复制或直接使用,确保外部无法再通过原数组影响集合。

当需要基于已有列表创建不可变副本时,可以配合 toArray 或直接把集合传给 List.of。但要注意,如果原集合包含 null,List.of 会立即失败,这比事后才发现数据异常更安全。

Map.of 与 Map.ofEntries 的使用

Map 的不可变创建稍微复杂一些,因为需要键值对。Map.of 提供了最多十个键值对的重载,而超过十个时要用 Map.ofEntries 配合 Map.entry 来构造。

import java.util.Map;

public class ImmutableMapDemo {
    public static void main(String[] args) {
        // 创建包含两个键值对的不可变 Map
        Map<String, Integer> scores = Map.of("Math", 90, "English", 85);

        System.out.println(scores);

        // 超过十个键值对时使用 ofEntries
        Map<String, String> config = Map.ofEntries(
            Map.entry("host", "127.0.0.1"),
            Map.entry("port", "8080"),
            Map.entry("env", "dev")
        );

        System.out.println(config);

        // 修改会抛出异常
        try {
            config.put("env", "prod");
        } catch (UnsupportedOperationException e) {
            System.out.println("Map 不可修改: " + e);
        }
    }
}

Map.of 内部对少量键值对做了专门的优化实现,比如 ImmutableCollections.Map1 到 MapN,查找效率很高。同时键和值都不允许为 null,否则构造时就会报错,这能有效防止后续出现空指针问题。

如果键重复,Map.of 会在构建时抛出 IllegalArgumentException,而不是静默覆盖,这一点也比普通的 HashMap 构造更严格,适合用来固化配置参数。

与传统不可变方式的对比

在 of 方法出现之前,常见的做法是先建可变集合,再用 Collections.unmodifiableXXX 包装。下面用表格说明两者差异。

对比项Collections.unmodifiableListList.of / Map.of
底层是否可变底层仍指向原可变集合自身真正不可变
null 元素允许(取决于原集合)不允许
代码简洁度需先创建再包装一行工厂方法
重复键/修改包装后修改抛异常构造即定稿,修改必抛异常

可以看到,of 系列不仅是语法糖,更在语义上明确了集合的不可变身份。若原可变集合被意外保留引用,unmodifiable 包装其实并不安全,而 of 返回的对象从根源切断了修改通道。

在方法返回值场景中,直接返回 List.of(result) 可以避免调用方修改内部数据;而返回 unmodifiableList 时,若内部列表引用泄露,依然存在风险。

适用场景与注意事项

不可变集合非常适合作为常量配置、多线程共享数据、API 返回对象。比如在 Spring 应用中,把状态码映射写成 Map.of,既清晰又不用担心被业务代码误改。

需要注意的是,of 创建的集合虽然元素不可变,但如果元素本身是可变对象,比如自定义类中含 setter,那么集合外仍可通过修改对象内部状态来改变“逻辑内容”。因此不可变集合保证的是引用不可变,而非深层不可变。对于敏感数据,应确保元素自身也是不可变类。

小结

List.of 与 Map.of 是 Java 现代化集合操作的重要补充,用极简语法提供真正不可变、-null 禁止、线程友好的集合实例。相比传统的 unmodifiable 包装,它们在安全性和表达力上都更优。理解其异常行为、null 限制以及元素可变性边界,能帮助开发者在合适的地方放心使用不可变集合,减少隐蔽的数据错误。

不可变集合List_ofMap_of修改时间:2026-08-06 23:12:14

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。