他们为什么决定让接口具有“可选操作”

ImmutableSet实现了Set接口。 对ImmutableSet没有意义的函数现在称为Set “Optional Operations”。 我假设这样的情况。 因此, ImmutableSet现在会为许多可选操作抛出UnsupportedOperationException

这似乎是我的倒退。 我被告知接口是一个契约,因此您可以在不同的实现中使用强制function。 可选操作的方法似乎从根本上改变(矛盾?)接口的意图。 今天实现这一点我将Set Interface分为两个接口:一个用于不可变操作,另一个用于扩展mutator的操作。 (很快,脱掉袖口解决方案)

我知道技术会发生变化。 我不是说它应该以某种方式完成。 我的问题是,这种变化是否反映了Java的一些基本理念的变化? 它是否只是一个让后退兼容的乐队? 我对Interfaces的理解不完整吗?

Java Collections API Design FAQ详细解答了这个问题:

问:为什么不直接在核心集合接口中支持不可变性,以便您可以取消可选操作(和UnsupportedOperationException)?

答:这是整个API中最具争议的设计决策。 显然,静态(编译时)类型检查是非常需要的,并且是Java中的标准。 如果我们认为可行,我们会支持它。 遗憾的是,尝试实现此目标会导致接口层次结构的大小爆炸,并且无法成功消除对运行时exception的需求(尽管它们会大幅减少)。

Doug Lea编写了一个流行的Java集合包,它确实反映了其界面层次结构中的可变性区别,不再认为它是一种可行的方法,基于用户对其集合包的体验。 用他的话来说(来自个人信件)“就像我说的那样痛苦,强大的静态类型对Java中的集合接口不起作用。”

为了说明血腥细节中的问题,假设您想要将可修改性的概念添加到层次结构中。 您需要四个新接口:ModifiableCollection,ModifiableSet,ModifiableList和ModifiableMap。 以前简单的层次结构现在是一个混乱的层次结构。 此外,您需要一个新的Iterator接口,用于不可修改的集合,不包含remove操作。 你现在可以取消UnsupportedOperationException吗? 不幸的是不是

考虑数组。 它们实现了大部分List操作,但没有删除和添加。 它们是“固定大小”的列表。 如果要在层次结构中捕获此概念,则必须添加两个新接口:VariableSizeList和VariableSizeMap。 您不必添加VariableSizeCollection和VariableSizeSet,因为它们与ModifiableCollection和ModifiableSet相同,但您可以选择添加它们以保持一致性。 此外,您还需要一种不支持添加和删除操作的新型ListIterator,以及不可修改的List。 现在我们有十到十二个接口,加上两个新的Iterator接口,而不是原来的四个接口。 我们完了吗? 没有。

考虑日志(例如错误日志,审计日志和可恢复数据对象的日志)。 它们是自然的仅附加序列,支持除remove和set(replace)之外的所有List操作。 它们需要一个新的核心接口和一个新的迭代器。

那么不可变的集合呢,而不是不可修改的集合呢? (即,客户无法更改的集合,并且不会因任何其他原因而更改)。 许多人认为这是所有内容中最重要的区别,因为它允许多个线程同时访问集合而无需同步。 将此支持添加到类型层次结构需要另外四个接口。

现在我们有大约20个接口和5个迭代器,而且几乎可以肯定的是,在实践中仍然存在一些不完全适合任何接口的集合。 例如,Map返回的集合视图是自然删除集合。 此外,有些集合会根据它们的值拒绝某些元素,因此我们仍然没有废除运行时exception。

完成所有工作之后,我们认为通过提供一组可以引发运行时exception的非常小的核心接口来回避整个问题是一个合理的工程折衷方案。

简而言之,使用Set和可选操作之类的接口来防止所需的不同接口数量呈指数级增长。 它不像“不可变”和“可变”那么简单。 然后,Guava的ImmutableSet必须实现Set以与使用Set的所有其他代码互操作。 它并不理想,但实际上没有更好的方法。