Collections.emptyMap()vs new HashMap()

什么是一些情况下,我可以使用Collections.emptyMap() ? 文档说我可以使用这个方法,如果我想我的集合是不可变的。

为什么我要一个不可变的空集合? 有什么意义?

有效Java中项目#43"Return empty arrays or collections, not null"演示返回一个空的集合,甚至可能演示如何在Collections类上使用这些emptyList()emptySet()emptyMap()方法来获得一个空集合也具有不变的额外好处。 从项目#15 "Minimize Mutability"

来自Collections-emptySet-Collections-emptyList-Collections

它是一种编程习惯用法。 这是为不想要空variables的人。 所以在集合初始化之前,他们可以使用空集。

注意:下面的代码只是一个例子(根据您的使用情况进行更改):

 private Set myset = Collections.emptySet(); void initSet() { myset = new HashSet(); } void deleteSet() { myset = Collections.emptySet(); } 

这些方法提供了一些优点:

  1. 它们更简洁,因为您不需要明确地输出集合的genericstypes,通常只是从方法调用的上下文中推断出来的。

  2. 他们更有效率,因为他们不打扰创造新的对象; 他们只是重新使用现有的空的和不可变的对象。 这种影响通常很小,但偶尔(很less很重要)。

诚然,根据我个人的经验,在API需要收集参数的情况下非常有用,但是您没有什么可提供的。 例如,你可能有一个像这样的API,不允许空引用:

 public ResultSet executeQuery(String query, Map<String, Object> queryParameters); 

如果你有一个不带任何参数的查询,创build一个HashMap(包括分配一个数组),当你可以传入一个实际上是一个常量的Empty Map时,在java.util.Collections

为什么我要一个不可变的空集合? 有什么意义?

这里有两个不同的概念,在一起看时显得很奇怪。 当你分别对待这两个概念时,这会更有意义。

  • 首先,你应该更喜欢使用一个不可变的集合,而不是一个可变的集合。 其他地方记载了不可抗拒性的好处。

  • 其次,你应该更喜欢使用一个空的集合,而不是使用null作为一个哨兵。 这里有很好的描述 。 这意味着你将有更清洁,更容易理解的代码,更less的地方隐藏错误。

所以当你有需要地图的代码时,最好传递一个空的地图而不是null来表示没有地图。 大多数情况下,当您使用地图时,最好使用不可变的地图。 所以这就是为什么有一个方便的function,使一个不变的空地图。

有些情况下,您更喜欢使用不可变的映射,列表,集合或其他types的集合。

首先可以说是最重要的用例就是每当你返回一个查询结果或一个返回一个结果集合(或列表或映射)的计算结果时,你应该更喜欢使用不可变的数据结构。

在这种情况下,我更喜欢返回这些不可变的版本,因为这更清楚地反映了计算结果集的事实上的不变性 – 不pipe你以后对数据做了什么,你从查询中得到的结果集都不应该更改。

第二个常见用例是当你需要提供一个参数作为方法或服务的input时。 除非你期望input集合被服务或方法修改(这通常是一个非常糟糕的devise思路),在许多情况下,传递一个不可变集合而不是可变集合可能是合理和安全的select。

我认为这是“按价值传递”的惯例。

更一般地说 – 当数据跨越模块或服务边界时,使用不可变的数据结构是明智的做法。 这使得(不可变的)input/输出和可变的内部状态之间的区别变得容易得多。

作为一个非常有益的副作用是提高您的模块/服务的安全性和线程安全性,并确保更清晰地分离问题。

另一个使用Collections.empty*()方法的好理由是它们明显缺乏冗长。 在Java7以前的时代,如果你有一个通用的集合,你必须在整个地方撒上genericstypes的注释。

只要比较这两个声明:

 Map<Foo, Comparable<? extends Bar>> fooBarMap = new HashMap<Foo, Comparable<? extends Bar>>(); 

与:

 Map<Foo, Comparable<? extends Bar>> fooBarMap = Collections.emptyMap(); 

后者显然在两个重要方面赢得了可读性的低下:

  1. 在第一个声明中,一个空映射的整个实例被埋在genericstypes声明的噪声中,使得一个基本上不重要的声明比它所需要的更加隐蔽。
  2. 除了在右侧缺less通用types注释之外,第二个版本明确指出地图被初始化为空的地图。 另外 – 知道这个方法返回一个不可变的映射,现在我更容易通过search/fooBarMap =/来findfooBarMap被分配了另一个非空的值。

首先,您可以参考共享。 一个new HashMap()等将需要一个分配的对象,并可能有一些额外的元素来保存数据,但你只需要一个不可变的空集合(列表,集合,映射或任何其他类似)的副本。 当你正在调用的方法需要接受一个Map,但不需要编辑它时,这使它成为一个明显的select。

我build议查看Josh Bloch的Effective Java ,其中列出了不可变对象的一些非常好的属性(包括线程安全性)。

当你有一个函数返回一个immutable collection并且在某些情况下没有数据返回,所以你可以返回null ,而不是返回emptyMap()

它使您的代码更容易,并防止NullPointerException

为什么我要一个不可变的空集合? 有什么意义?

出于同样的原因,你可以在某些时候使用Collections.unmodifiableMap() 。 你想要返回一个Map实例,如果用户试图修改它,会抛出一个exception。 这只是一个特例:空的地图。

大多数时候我们使用一个constructor来创build一个新的empty map 。 但是Collections methods提供了一些优点来使用static method java.util.Collections.emptyMap()创build一个empty map

  1. 它们更简洁,因为您不需要明确地输出集合的genericstypes,通常只是从方法调用的上下文中推断出来的。

  2. 他们更有效率,因为他们不打扰创造新的对象; 他们只是重新使用现有的空的和不可变的对象。 这种影响通常很小,但偶尔(很less很重要)。

为什么我要一个不可变的空集合? 有什么意义?

出于同样的原因,你可能需要不可变的对象。 主要是因为你可以在晚上安全睡觉,知道多个线程可以访问同一个对象的实例,并且他们都将看到相同的值。 在集合中没有任何项目仍然是一个有效的值,你想要维护。