常用API中Collections_unmodifiable不可变集合封装

浅杰酱_1680

浅杰酱_1680

2026-03-31

356人浏览

原创

collections.unmodifiablexxx 返回的是不可修改的包装视图,不复制数据,原始集合被修改时视图会反映变化或抛异常;jdk 9+ 的 list.of() 等才创建真正不可变集合。

常用api中collections_unmodifiable不可变集合封装

Java 中 Collections.unmodifiableXXX 系列方法(如 unmodifiableList、unmodifiableSet、unmodifiableMap)是创建不可变集合视图最常用的方式,但它们只是“不可修改的包装”,不是真正意义上的不可变集合。

不可变包装的本质是防御性代理

这些方法返回的是原集合的一个只读代理对象,底层仍引用原始集合。一旦原始集合被外部修改,不可变视图会立即反映变化,甚至可能抛出 ConcurrentModificationException。

  • 它不复制数据,仅拦截 add、remove、clear 等修改操作并抛出 UnsupportedOperationException
  • 如果原始集合是线程不安全的,且被并发修改,不可变视图的行为是未定义的
  • 对 unmodifiableMap 的 keySet()、values()、entrySet() 返回的集合也仍是可变的(除非显式再包装)

常见误用:以为“封装了就安全”

开发者常误以为只要调用了 unmodifiableList(list),返回值就彻底安全,从而忽略原始引用泄漏问题。

  • 错误示例:return Collections.unmodifiableList(internalList); —— 若 internalList 是类成员且被其他代码持有,它仍可能被修改
  • 正确做法:先拷贝再包装,例如 return Collections.unmodifiableList(new ArrayList(internalList));
  • 对于 Map,需注意:key 和 value 本身是否可变(如 value 是可变对象,即使 Map 不可变,其状态仍可变)

替代方案:更可靠的不可变集合选择

JDK 9+ 提供了 List.of()、Set.of()、Map.of() 等工厂方法,它们创建的是真正不可变、紧凑且线程安全的集合。

  • 它们在创建时即固化数据,不保留对原始容器的引用
  • 空值受限(如 Set.of(null) 抛异常),有助于早期暴露问题
  • 若需从已有集合构造,可用 List.copyOf(existingList)(JDK 10+),它会自动处理 null 检查和不可变封装

使用建议与边界注意

除非明确需要“视图语义”(比如动态反映底层变化),否则优先选用 JDK 9+ 的不可变工厂方法或 Guava 的 ImmutableList 等。

  • 不要对 unmodifiableXXX 的结果做类型强转(如转回 ArrayList),这是无效且危险的
  • 调试时可通过 IDE 查看实际类名(如 UnmodifiableRandomAccessList),确认是否为包装类
  • 若需深度不可变(含嵌套对象),需额外确保元素自身不可变,或手动深拷贝

大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
guava包作用
guava包作用

guava是一个java库,增强了java标准库,提供更有效率和易于使用的集合、实用程序、缓存和并发工具。想了解更多guava的相关内容,可以阅读本专题下面的文章。

2024.05.29

4451

6

c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

2023.09.22

529

3

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

2024.03.01

1658

6

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

2023.08.10

3618

6

golang map内存释放
golang map内存释放

本专题整合了golang map内存相关教程,阅读专题下面的文章了解更多相关内容。

2025.09.05

450

5

golang map相关教程
golang map相关教程

本专题整合了golang map相关教程,阅读专题下面的文章了解更多详细内容。

2025.11.16

323

7

golang map原理
golang map原理

本专题整合了golang map相关内容,阅读专题下面的文章了解更多详细内容。

2025.11.17

493

20

java判断map相关教程
java判断map相关教程

本专题整合了java判断map相关教程,阅读专题下面的文章了解更多详细内容。

2025.11.27

263

6

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.6万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.3万人学习