不可修改映射(Java 集合)与不可变映射(Google)

背景

我需要返回一个用于数据缓存的映射的引用,我想确保没有人可以修改它们的引用。

提问

我已经在网上看到了很多关于不可修改映射和不可变映射的引用,但是我没有看到任何关于它们的比较和对比。我认为谷歌/番石榴创建自己的版本是有充分理由的——有人能告诉我这是什么吗?

145094 次浏览

番石榴文件

JDK 提供了 Collections.unmodifiableXXX方法,但是在我们看来,这些方法可能是笨重和冗长的; 在任何地方使用防御性副本都会让人感到不安全: 返回的集合只有在没有人引用原始集合效率低下的情况下才是真正不可变的: 数据结构仍然有可变集合的所有开销,包括并发修改检查、散列表中的额外空间等等。

看一下 ImmutableMapJavaDoc: 医生

那里有关于这方面的信息:

与 Collections.unmodfiableMap (java.util)不同。Map) ,这是一个仍然可以更改的单独映射的视图,ImmutableMap 的实例包含自己的数据,并且永远不会更改。ImmutableMap 对于公共静态最终映射(“常量映射”)非常方便,并且允许您轻松地对调用者提供给您的类的映射进行“防御性复制”。

ImmutableMap 不接受 null值,而 Collections.unmodifiableMap()接受。此外,它永远不会改变后,建设,而 UnmodifiableMap可能。来自 JavaDoc:

一个不可变的、基于散列的 Map,具有可靠的用户指定的迭代顺序。不允许空键或值。

与 Collections.unmodfiableMap (java.util)不同。Map) ,这是一个仍然可以更改的单独映射的视图,ImmutableMap 的实例包含自己的数据,并且永远不会更改。ImmutableMap 对于公共静态最终映射(“常量映射”)非常方便,并且允许您轻松地对调用者提供给您的类的映射进行“防御性复制”。

一个不可修改的地图仍然可能改变。它只是一个 风景在一个可修改的地图,和变化的背景地图将是可见的,通过不可修改的地图。不可修改的映射只能防止那些只有不可修改的视图参考的修改:

Map<String, String> realMap = new HashMap<String, String>();
realMap.put("A", "B");


Map<String, String> unmodifiableMap = Collections.unmodifiableMap(realMap);


// This is not possible: It would throw an
// UnsupportedOperationException
//unmodifiableMap.put("C", "D");


// This is still possible:
realMap.put("E", "F");


// The change in the "realMap" is now also visible
// in the "unmodifiableMap". So the unmodifiableMap
// has changed after it has been created.
unmodifiableMap.get("E"); // Will return "F".

与此相反,Guava 的 ImmutableMap 实际上是 永恒不变: 它是给定 map 的真正 收到,任何人都不能以任何方式修改这个 ImmutableMap。

更新 :

正如在 comment中指出的,也可以使用标准 API 创建不可变映射

Map<String, String> immutableMap =
Collections.unmodifiableMap(new LinkedHashMap<String, String>(realMap));

这将在给定映射的真实副本上创建一个不可修改的视图,因此可以很好地模拟 ImmutableMap的特征,而不必向 Guava 添加依赖项。