emptyList()vs empty Set(),如果需要Collection的实例,有没有理由选择其中一个?

时间:2014-06-30 13:56:54

标签: java collections

JDK 中,有Collection.emtpyList()Collection.emptySet()。两者都在他们自己的权利。但有时候所需要的只是一个空的,不可变的Collection实例。对我来说,没有理由选择一个而不是另一个,因为它们以有效的方式实现Collection的所有操作并且具有相同的结果。然而,每当我需要这样一个空集合时,我会思考哪一个用于两分之一。

我不希望从这个问题的答案中更深入地理解集合框架,但也许有一个微妙的理由我可以用来证明选择一个而不考虑另一个关于它再次。

在他们功能相同的情况下,答案应至少说明一个Collection.emtpyList()Collection.emptySet()之一优先于另一个的原因。答案是如果陈述的理由接近此列表的顶部,则更好:

  • 在某种情况下,类型系统比其中一种更快乐(例如,类型推断允许更短的代码而不是另一种代码)。

  • 存在性能差异,可能在某些特殊情况下(例如,如果将空集合作为参数传递给某些集合框架的静态或实例方法,如Collections.sort()或{ {1}})。

  • 选择其中一个"更有意义"在一般情况下,如果你考虑一下。

出现此问题的示例

为了给出一些上下文,这里有两个例子,我需要一个空的,不可修改的集合。

这是一个API的示例,它允许通过可选地指定创建中使用的对象集合来创建某个对象。第二种方法只使用空集合调用第一种方法:

Collection.removeAll()

这是一个实体的示例,其状态由存储在非最终字段中的不可变集合表示。初始化时,字段应设置为空集合:

static void createObjectWithTheseThings(Collection<Thing> things) {
    ...
}

static void createObjectWithoutAnyThings() {
    createObjectWithTheseThings(Collections.emptyXXX());
}

3 个答案:

答案 0 :(得分:3)

不幸的是,我没有一个能够成为优先列表顶部的答案,但如果我是你,我会选择

Collections.emptySet
  • 类型推断是您的首要任务,但我不知道如果您正在寻找一个emptyCollection()

  • ,该选择是否可以/应该影响
  • 在第二个优先级上,考虑一个api,它接收一个基于传入的具体对象的子接口以不同方式(意外/有意)执行的集合。他们是否更有可能提供各种各样的基于具体实现的性能(与ArrayList或LinkedList一样)代替?无论如何,空集/列表不会在任何空数据结构上建模;它们是虚拟实现 - 因此没有真正的区别

  • 基于java对这些接口的建模(这无疑是不理想的),Collection与Set非常相似。事实上,我认为这些方法几乎完全相同。逻辑上它看起来还不错,List是特定子类型,增加了额外的排序问题。

现在Collection和Set看起来非常相似(java-wise)提出了一个问题。如果您使用的是Collection类型,很明显它不是您想要的列表。现在问题是你确定你不是指一套。如果你不这样做,那么你是否正在使用像 Bag 这样的东西(当然必须有整体逻辑中不为空的具体实例)。所以,如果你担心说 Bag ,那么不应该由Bag api提供一个emptyBag()方法吗?就是想。顺便说一下,我同时坚持使用emptySet():)

答案 1 :(得分:1)

对于emptyXXX(),它实际上并不重要 - 因为它们都是空的(并且它们是不可修改的,所以它们总是保持空白)它根本不重要。它们同样适用于所有收集活动。

看一下Collections真正为您提供的内容:特殊实现(实例在调用之间共享!)。所有相关操作都是虚拟实现,可以返回常量结果或立即抛出。即使是iterator()也只是一个没有状态的假人。

它根本不会产生任何显着的差异。

编辑:你可以说对于emptyList / Set的特殊情况,它们在Collecton接口级别的语义和复杂性相同。 Collection上可用的所有操作都由emptySet / List实现为O(1)操作。由于他们遵循Collection定义的合同,因此它们在语义上也是相同的。

答案 2 :(得分:1)

我能想象的唯一情况就是如果使用你的Collection的代码做了这样的事情:

Collection<T> collection = ...
List<T> asAList;
if (collection instanceof List) {
    asAList = (List<T>) collection;
} else {
    asAList = new ArrayList<T>(collection);
}

显然在这种情况下你会想要使用emptyList(),而如果秘密目标类型是Set,你需要emptySet()

否则,就“更有意义”而言,我同意@ ac3的逻辑,即通用Collection就像一个Bag,而一个空的不可变Set和空的不可变Bag几乎是一回事。但是,非常习惯使用不可变列表的人可能会更容易想到这些。