为什么JCF接口中的许多方法在Java 8中没有默认?

时间:2014-02-13 15:13:15

标签: java collections java-8 default-method

Collection界面的最低完整定义仅包含两种方法:iterator()size(),这些方法在AbstractCollection中是抽象的。

为什么所有其他方法都没有在Java 8中默认?兼容性应该不是问题,例如,Iterator.remove()在Java 7之前是抽象的,但是从Java 8开始就是默认的。

当我希望AbstractCollection实现成为另一个类层次结构的成员时,有时候来自Collection的子类很不方便。这不是Java中实际需要接口中的默认方法的原因之一吗?

关于MapList和其他基本接口的相同问题,包括Java Collection Framework。

更新

保罗·桑多兹:

  

一般来说,如果有一个令人信服的理由来帮助实现,我们只会将接口上的现有抽象方法转换为非抽象方法,例如Iterator.remove。

     

这些不是Collection上的新方法,并且AbstractCollection中已经有实现。将这些抽象转换为非抽象方法的优势并不是特别引人注目,因为它最有可能从AbstractCollection继承或提供更有效的实现。

     

可以将AbstractCollection上的所有非抽象方法移动到Collection。如果我们从一张白纸开始,这是我们可能做的。 (注意,对于AbstractList上的所有非抽象方法都不能这样做。)

http://mail.openjdk.java.net/pipermail/core-libs-dev/2014-February/025118.html

1 个答案:

答案 0 :(得分:5)

默认方法的主要目标是实现接口的兼容演进。请参阅State of the Lambda文档的第10部分。这种演变的主要方向之一是促进内部迭代。请参阅State of the Lambda: Libraries Edition内部与外部迭代部分。为此,有Iterable.forEachCollection.removeIfList.replaceAll等新方法。

添加了List.sort之类的其他方法,因为它允许单独的具体列表实现提供更有效的排序算法,这不能用Collections.sort完成。

最后,为了方便起见,添加了默认方法,例如Iterator.remove。多年来,我们和其他许多人都非常恼火地添加了一个方法remove,只要我们每次实施新的UnsupportedOperationException时都会抛出Iterator。默认方法remove为我们执行此操作。请注意,这个方法实际上并没有删除任何元素。 (怎么会这样?)

为一堆Collection方法提供默认实现似乎很方便,这些方法是根据iterator等其他方法编写的。但是,我不认为它非常有用,事实上我不确定某些方法是否可行。

考虑Collection.contains(Object)方法。可以想象,通过逐步执行每个元素并比较相等性,可以用iterator来编写默认的实现。对于类似TreeSetHashSet的内容,这将是一个非常糟糕的实现。即使具体的List实现(例如LinkedListArrayList)也提供了快速路径实现,它比步进迭代器更有效。具有Collection.contains的默认实现可能有点方便,但实际上,它并没有增加太多价值。实际上,每个集合都希望覆盖它。

现在考虑equalsCollection.equals的{​​{3}}提出了一系列微妙的问题。简而言之,Set只能等于另一个SetList只能等于另一个Listequals操作必须是对称的。因此,既不是Collection也不是List的{​​{1}}永远不能等于SetList

好的,所以我们的Set默认方法必须预先进行一堆Collection.equals检查。如果两者都是instanceof,我们可以委托给Lists,如果两者都是AbstractList.equals,我们可以委托给Sets。现在让我们假设这个对象和另一个对象既不是AbstractSet.equals也不是Lists。如果它们是不同的具体实现并且彼此不相等会怎样?我们无法分辨。

除此之外,让我们假设我们将等式定义为具有相同的成员资格。我们唯一能做的就是遍历每个集合。但是我们不能(通常)对迭代次序做出任何假设,因此我们不能同时迭代它们并像对于列表那样成对地比较元素。相反,我们必须将一个集合中的所有元素加载到某种临时集合中。它不能是Sets,因为我们可能有重复项。然后我们检查另一个Set的每个元素,以确保其中的每个元素都在第一个元素中,并且第一个元素中没有额外元素。这不是非常困难,但它很昂贵,并且不支持某些语义,如订单敏感度。

我无法想象任何具体的集合子类实际上都想要使用这种算法。


总之,使用默认方法简化集合实现并不是默认方法的设计目标之一。此外,尽管在Collection上提供默认方法似乎很方便,但它们实际上看起来并不实用。任何合理的Collection实现都需要覆盖所有方法,以便提供它想要的语义而不会非常低效。