Java 实现不可变Map
有时不希望修改java.util.Map,如线程间的共享数据。为此我们可以使用Unmodifiable Map 或 Immutable Map。本文讨论两者之间差异,然后给出不同方式创建不可变Map示例。
1. Unmodifiable vs Immutable
不可修改map是对map的包装,它不允许对其进行直接修改:
Map<String, String> mutableMap = new HashMap<>();
mutableMap.put("USA", "North America");
Map<String, String> unmodifiableMap = Collections.unmodifiableMap(mutableMap);
assertThrows(UnsupportedOperationException.class, () -> unmodifiableMap.put("Canada", "North America"));
但我们仍然可以改变其底层的map,从而变形修改了上层的不可修改map:
mutableMap.remove("USA");
assertFalse(unmodifiableMap.containsKey("USA"));
mutableMap.put("Mexico", "North America");
assertTrue(unmodifiableMap.containsKey("Mexico"));
我们希望不可变map包含它自己的私有数据,并且不允许对其进行修改。因此一旦创建了不可变map的实例,数据就不能以任何方式更改。
2. Guava’s Immutable Map
Guava提供不可修改map的实现ImmutableMap。如果尝试修改其数据会抛出UnsupportedOperationException 异常。因为其包括私有数据,当原始map被改变时该私有数据也不能被修改。下面讨论不同方式创建ImmutableMap:
2.1 使用copyOf() 方法
首先使用ImmutableMap.copyOf()方法,返回原始map中元素的拷贝:
ImmutableMap<String, String> immutableMap = ImmutableMap.copyOf(mutableMap);
assertTrue(immutableMap.containsKey("USA"));
这是不能对其进行直接或间接修改:
assertThrows(UnsupportedOperationException.class,
() -> immutableMap.put("Canada", "North America"));
mutableMap.remove("USA");
assertTrue(immutableMap.containsKey("USA"));
mutableMap.put("Mexico", "North America");
assertFalse(immutableMap.containsKey("Mexico"));
2.2 使用builder() 方法
也可以使用ImmutableMap.builder()方法创建原始map的元素拷贝。该方法可以增加新的元素,但不会影响原始map:
ImmutableMap<String, String> immutableMap = ImmutableMap.<String, String>builder()
.putAll(mutableMap)
.put("Costa Rica", "North America")
.build();
assertTrue(immutableMap.containsKey("USA"));
assertTrue(immutableMap.containsKey("Costa Rica"));
与前面示例一样,不能直接或间接修改:
assertThrows(UnsupportedOperationException.class,
() -> immutableMap.put("Canada", "North America"));
mutableMap.remove("USA");
assertTrue(immutableMap.containsKey("USA"));
mutableMap.put("Mexico", "North America");
assertFalse(immutableMap.containsKey("Mexico"));
2.3 使用of() 方法
最后我们使用ImmutableMap.of() 方法创建不可变map,创建时带一组元素,但最多不能超过5个键值对:
ImmutableMap<String, String> immutableMap
= ImmutableMap.of("USA", "North America", "Costa Rica", "North America");
assertTrue(immutableMap.containsKey("USA"));
assertTrue(immutableMap.containsKey("Costa Rica"));
当然也不能修改:
assertThrows(UnsupportedOperationException.class,
() -> immutableMap.put("Canada", "North America"));
3. 总结
本文我们讨论了不能修改map和不能改变map之间差异。同时提供几种方式创建Guava’s ImmutableMap。
本文参考链接:https://blog.csdn.net/neweastsun/article/details/109522289