关于java:Collections.emptyMap()vs new HashMap()

Collections.emptyMap() vs new HashMap()

我可以在哪些情况下使用Collections.emptyMap()?文档中说,如果希望集合不可变,可以使用此方法。

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


从有效的Java中,Typeα43(EDCOX1)1表示要返回一个空集合,甚至可能演示使用这些EDCOX1、2、EDCOX1、3、EDCX1、4个方法在集合类中获得一个空集合,这也具有不可变的额外好处。来自项目15 "Minimize Mutability"

从集合EmptySet集合EmptyList集合

Its a type of programming idiom. This is for people that do not want null variables. So before the set gets initialized, they can use the empty set.

注意:下面的代码只是一个例子(根据您的用例更改它):

1
2
3
4
5
6
7
8
private Set myset = Collections.emptySet();

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

这些方法有两个优点:

  • 它们更简洁,因为您不需要显式地键入集合的泛型类型——通常只是从方法调用的上下文推断出来的。

  • 它们效率更高,因为它们不需要创建新对象;它们只是重用现有的空的和不变的对象。这种影响通常很小,但偶尔(好吧,很少)很重要。


  • 诚然,在我个人的经验中,它在API需要参数集合但您没有提供的情况下非常有用。例如,您可能有这样一个API,它不允许空引用:

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

    如果您有一个不带任何参数的查询,那么创建一个hashmap肯定有点浪费,它涉及到分配一个数组,当您可以传入一个"空映射"时,它实际上是一个常量,它在java.util.Collections中实现的方式。


    Why would I want an immutable empty collection? What is the point?

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

    • 首先,您应该尽可能使用不可变集合,而不是可变集合。不动产的好处在别处有很好的记载。

    • 其次,您应该更喜欢使用空集合,而不是将空集合用作哨兵。这里很好地描述了这一点。这意味着您将拥有更干净、更容易理解的代码,而隐藏bug的地方更少。

    因此,当您有需要映射的代码时,最好传递一个空映射,而不是一个空映射来表示没有映射。大多数时候,当你使用一个地图时,最好使用一个不变的地图。所以这就是为什么有一个方便的函数来生成一个不变的空映射。


    在某些情况下,您更喜欢使用不可变的映射、列表、集合或其他类型的集合。

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

    在这种情况下,我更倾向于返回这些不可变的版本,因为这更清楚地反映了计算结果集的事实不可变性-无论以后如何处理数据,从查询中收到的结果集都不应更改。

    第二个常见的用例是当您需要提供一个参数作为方法或服务的输入时。除非您希望输入集合被服务或方法修改(这通常是一个非常糟糕的设计思想),否则在许多情况下,传入不可变集合而不是可变集合可能是合理和安全的选择。

    我认为这是"传递价值"的惯例。

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

    这样做的一个非常有益的副作用是提高模块/服务的安全性和线程安全性,并确保更清晰地分离关注点。

    使用Collections.empty*()方法的另一个很好的原因是它们明显缺乏语言。在Java7之前的时代,如果您有一个通用的集合,那么您必须将通用的类型注释散布到整个地方。

    只需比较这两个声明:

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

    对比:

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

    后者显然以两种重要方式赢得可读性:

  • 在第一个声明中,空映射的整个实例化都隐藏在泛型类型声明的噪声中,这使得一个基本上微不足道的声明比它需要的要神秘得多。
  • 除了在右侧明显缺少泛型类型注释之外,第二个版本还清楚地声明映射已初始化为空映射。另外,知道这个方法返回一个不变的映射,现在只需搜索/fooBarMap =/就可以更容易地找到fooBarMap被分配到另一个非空值的位置。

  • 首先,你可以通过分享参考资料来摆脱困境。new HashMap()等将需要一个已分配的对象,可能还需要一些额外的元素来保存数据,但您只需要一个不可变的空集合(list、set、map或任何其他类似集合)的副本。当您调用的方法需要接受一个映射但不需要编辑它时,这使得它成为一个明显的选择。

    我建议检查一下Josh Bloch的有效Java,它列出了一些不可变对象(包括线程安全)的非常好的属性。


    当您有返回immutable collection的函数,并且在某些情况下没有要返回的数据时,它是有用的,因此您可以返回emptyMap(),而不是返回null

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


    大多数时候,我们使用一个constructor来创建一个新的empty map。但是,Collectionsmethods为使用staticmethodjava.util.Collections.emptyMap()创建empty map提供了一些优势。

  • They're more concise because you don't need to explicitly type out the generic type of the collection - it's generally just inferred from
    the context of the method call.

  • They're more efficient because they don't bother creating new objects; they just re-use an existing empty and immutable object. This
    effect is generally very minor, but it's occasionally (well, rarely)
    important.


  • Why would I want an immutable empty collection? What is the point?

    出于同样的原因,您在某些时候会使用Collections.unmodifiableMap()。您希望返回一个映射实例,该实例在用户尝试修改异常时引发异常。这只是一个特例:空地图。


    Why would I want an immutable empty collection? What is the point?

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