Collections.emptyMap()与新的HashMap()


143

我可以使用哪些情况Collections.emptyMap()?文档说,如果我希望我的收藏集是不可变的,则可以使用此方法。

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


12
为问题+1,因为我之前从未见过这种静态方法
Tim Bender

您也可以看看scala镜头google scala镜头。emptyMap和immutableMap可用于创建不可变的对象。emptyMap是初始点。每次添加元素时,地图本身都会被包含旧元素和新元素的地图替换。关键是,访问对象是安全的。
michael_s

1
就像Objective-C一样[NSArray array],它返回一个虽然不可用但存在的对象。因此,您可以像正常对象一样玩它,而不会出错。
Shane Hsu

Answers:


144

有效的Java项目#43 - "Return empty arrays or collections, not null"演示返回一个空的集合,甚至演示如何使用这些emptyList()emptySet()emptyMap()对集合类的方法来得到一个空的集合,也有保持不变的额外好处。从 项目#15开始 "Minimize Mutability"

来自Collections-emptySet-Collections-emptyList-Collections

它是一种编程习语。这适用于不希望使用null变量的人。因此,在初始化集合之前,他们可以使用空集合。

注意:以下代码仅是一个示例(根据您的用例进行更改):

private Set myset = Collections.emptySet();

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

这些方法具有两个优点:

  1. 它们更加简洁,因为您无需显式键入集合的泛型类型-通常仅从方法调用的上下文中进行推断。

  2. 它们效率更高,因为它们不必费心创建新对象。他们只是重复使用一个现有的空且不可变的对象。通常,这种影响很小,但偶尔(非常,很少)很重要。


15
+1为有效Java参考。一本尼特:我会建议参数化Set,并HashSet在你的例子,因为整点emptySet()方法和朋友(而不是常量Collections.EMPTY_SET等)是他们与仿制药发挥很好。另外,使用自Java 5以来不推荐使用的功能(原始类型)不是很好的教学辅助工具。
Daniel Pryden

4
我仍然不相信...使用a Collection而不是null避免Exceptions在后续操作中抛出的全部意图?我想,使用不可变的集合只会导致其他某种异常。和分配null肯定是不超过分配不变的常数效率较低。
fgysin恢复莫妮卡

14
@fgysin:如果您有一个API,期望客户端修改集合,那么可以,返回一个不可变的集合是没有意义的。但是,如果您有一个API,可以在其中返回一个客户端不得修改的集合,而应仅对其进行迭代,则将视图返回到基础集合是很有意义的,以确保“不良”客户端不会意外地修改拥有的集合由你。返回空集合而不是null意味着您的客户端在使用该集合之前不必进行null检查,从而使客户端代码更加清晰。
Jean Hominal

4
public boolean setExists() { return !myset.equals(Collections.emptySet()); }
assylias

5
在您的示例中,您正在显式检查空集并将其用作标记值,并且您的类是可变的。您的小例子使用了哨兵和可变性,这正是Collections.emptySet()试图防止的。
Marc O'Morain

33

根据我的个人经验,在API需要一组参数但您无所提供​​的情况下,它非常有用。例如,您可能有一个看起来像这样的API,并且不允许空引用:

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

如果您有一个不带任何参数的查询,那么创建一个HashMap肯定会浪费一点,这涉及到分配一个数组,而此时您只需传递“ Empty Map”(实际上是一个常量,即实现方式)即可在中java.util.Collections


22

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

一起查看时,这里有两个不同的概念看起来很奇怪。当您分别对待这两个概念时,这更有意义。

  • 首先,您应该尽可能使用不可变集合,而不是可变的集合。不动产的好处在其他地方有充分记载

  • 其次,您应该更喜欢使用空集合,而不是将null用作标记。这在这里很好的描述。这意味着您将拥有更加整洁,易于理解的代码,并且可以将错误隐藏的地方更少。

因此,当您有需要映射的代码时,最好传递一个空映射而不是一个空值以指示不存在映射。在大多数情况下,使用地图时,最好使用不可变地图。因此,这就是为什么有一个便利函数来制作不可变的空图的原因。


8

在某些情况下,您希望使用不可变的地图,列表,集合或其他类型的集合。

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

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

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

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

更笼统地说 -每当数据越过模块或服务边界时,使用不可变的数据结构是明智的做法。这使得推断(不可变的)输入/输出与可变内部状态之间的差异变得容易得多。

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

使用Collections.empty*()方法的另一个很好的理由是它们明显缺乏详细性。在Java7之前的时代,如果您有通用集合,则必须到处散布通用类型注释。

只需比较这两个声明:

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

与:

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

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

  1. 在第一个声明中,空映射的整个实例被掩盖在泛型类型声明中,这使得本质上琐碎的声明比需要的更加隐秘。
  2. 除了在右侧明显缺少通用类型注释外,第二个版本还明确指出该映射已初始化为空映射。另外,由于知道此方法会返回一个不变的映射,所以现在我更容易通过搜索来查找在何处fooBarMap被分配了另一个非空/fooBarMap =/

5

首先,您可以摆脱参考共享。一个new HashMap()etc需要一个分配的对象,可能还需要一些额外的元素来保存数据,但是您只需要一个不变的空集合的一个副本(列表,集合,映射或任何其他类似的集合)。当您要调用的方法需要接受Map而不需要对其进行编辑时,这使其成为显而易见的选择。

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


3

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

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


3

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

  1. 它们更加简洁,因为您无需显式键入集合的泛型类型-通常仅从方法调用的上下文中进行推断。

  2. 它们效率更高,因为它们不必费心创建新对象。他们只是重复使用一个现有的空且不可变的对象。通常,这种影响很小,但偶尔(非常,很少)很重要。



1

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.