Java 9 引入的不可变集合工厂方法在 JDK11 中如何使用
需要澄清的是,不可变集合工厂方法(List.of(), Set.of(), Map.of())实际上是在 Java 9 中引入的,JDK11 继续支持并广泛使用。若在 JDK8 项目中直接使用会导致编译错误,请务必确认项目 JDK 版本。
先说结论:这些工厂方法用于快速创建不可变集合,适合配置项、常量列表等无需修改的场景,能有效减少样板代码。
- 适合:初始化后不再修改的集合场景,如常量定义、配置读取。
- 先看:确认业务逻辑是否真的不需要添加或删除元素,避免后续报错。
- 建议:若需修改,可先创建不可变集合再包装为可变集合(如 new ArrayList<>(List.of(...)))。
版本兼容性检查
在使用这些 API 前,必须确保编译和运行环境不低于 Java 9。JDK8 及以下版本不支持此特性。
1. 命令行检查:
java -version
javac -version
输出应显示 version "11" 或更高(至少 9)。
2. 构建工具配置:
Maven 项目需在 pom.xml 中指定 source 和 target 版本:
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
Gradle 项目需在 build.gradle 中配置:
sourceCompatibility = '11'
targetCompatibility = '11'
完整代码示例
以下是一个完整的可运行 Main 类示例,涵盖了 List、Set、Map 的创建及 copyOf 用法,并包含了异常捕获演示。
import java.util.*;
public class ImmutableCollectionDemo {
public static void main(String[] args) {
// 1. 创建不可变 List
List<String> list = List.of("A", "B", "C");
System.out.println("List: " + list);
// 2. 创建不可变 Set
Set<String> set = Set.of("X", "Y", "Z");
System.out.println("Set: " + set);
// 3. 创建不可变 Map (键值对较少时)
Map<String, Integer> map = Map.of("key1", 1, "key2", 2);
System.out.println("Map: " + map);
// 4. 基于现有集合创建 (copyOf)
List<String> source = new ArrayList<>();
source.add("Copy");
List<String> copy = List.copyOf(source);
System.out.println("Copy: " + copy);
// 5. 验证不可变性 (尝试修改会抛出异常)
try {
list.add("D");
} catch (UnsupportedOperationException e) {
System.out.println("验证成功:不可变集合禁止修改,抛出 UnsupportedOperationException");
}
}
}
验证不可变性
创建集合后,可通过以下方式验证其是否真正不可变:
- 运行时测试:调用 add(), remove(), clear() 等方法,程序应抛出
java.lang.UnsupportedOperationException。 - 单元测试:在 JUnit 中使用 assertThrows 验证异常。
- Null 值检查:尝试传入 null 元素,构造时应直接抛出
java.lang.NullPointerException,而不是等到运行时。
常见坑与排查
- JDK 版本不匹配:如果在 JDK8 环境中编译代码使用 List.of(),会报错
cannot find symbol。解决方法是升级 JDK 或降低语言级别。 - 误以为可修改:使用 of() 创建的集合调用 add() 会直接报错。若后续需要修改,需包装一层,如
new ArrayList<>(List.of(...))。 - Null 值限制:这些工厂方法不允许包含 null 元素,而传统的 Arrays.asList() 允许,迁移时需注意。
- Map 键重复:Map.of() 不允许重复 key,否则会抛出
IllegalArgumentException,而普通 HashMap 允许覆盖。 - 元素数量限制:Map.of() 最多支持 10 个键值对,超过请使用
Map.ofEntries()。