在Java中的不可变的Map实现
1.概述
有时最好是不允许修改java.util.Map,比如跨线程共享只读数据。为此,我们可以使用Unmodifiable Map或Immutable Map。
在这个快速教程中,我们将看到它们之间有什么区别。然后,我们将介绍各种可以创建Immutable Map的方法。
2.不可更改与不可改变
不可修改的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"));
另一方面,Immutable Map包含它自己的私有数据,不允许对其进行修改。因此,一旦Immutable Map的实例被创建,数据就不能以任何方式改变了。
3. Guava的不可变Map
Guava为每个java.util.Map 使用ImmutableMap的不可变版本。每当我们试图修改它时,它就会抛出一个不支持操作的异常。
由于它包含自己的私有数据,所以当原始Map被改变时,这些数据不会改变。
我们现在将讨论创建ImmutableMap.的实例的各种方法。
3.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"));
3.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"));
3.3.使用of()方法
最后,我们可以使用ImmutableMap.of()方法来创建一个不可变映射,其中包含一组动态提供的条目。它最多支持五个键/值对:
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"));
4.总结
在这篇快速文章中,我们讨论了不可修改的Map和不可改变的Map之间的区别。
我们也看了一下创建Guava的ImmutableMap的不同方法。
而且,像往常一样,完整的代码示例可在GitHub上获得。