ImmutableSet实现Set接口。对ImmutableSet
没有意义的功能现在称为Set
的“可选操作”。我假设这样的情况。所以ImmutableSet
现在为许多可选操作抛出UnsupportedOperationException
。
这似乎是我的倒退。我被告知接口是一个契约,因此您可以在不同的实现中使用强制功能。可选操作的方法似乎从根本上改变(矛盾?)接口的意图。今天实现这一点我将Set
接口分成两个接口:一个用于不可变操作,另一个用于扩展这些操作用于mutators。 (很快,脱掉袖口解决方案)
我理解技术会发生变化。我不是说应该以这种或那种方式完成。我的问题是,这种变化是否反映了Java的一些基本理念的变化?让事情向后兼容只是更多的乐队吗?我对Interfaces的理解不完整吗?
答案 0 :(得分:9)
Java Collections API Design FAQ详细回答了这个问题:
问:为什么不直接在核心集合接口中支持不变性,以便您可以取消可选操作(和UnsupportedOperationException)?
答:这是整个API中最具争议的设计决策。显然,静态(编译时)类型检查是非常需要的,并且是Java中的标准。如果我们认为可行,我们会支持它。遗憾的是,尝试实现此目标会导致接口层次结构的大小爆炸,并且无法成功消除对运行时异常的需求(尽管它们会大幅减少)。
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返回的集合视图是自然删除集合。此外,有些集合会根据其值拒绝某些元素,因此我们仍然没有废除运行时异常。
当说完所有内容之后,我们认为通过提供一小组可以引发运行时异常的核心接口来回避整个问题是一个合理的工程折衷方案。
简而言之,使用Set
之类的接口和可选操作来防止所需的不同接口数量呈指数级增长。它并不像“不可变”和“可变”那么简单。然后,Guava的ImmutableSet
必须实现Set
才能与使用Set
s的所有其他代码互操作。它并不理想,但实际上没有更好的方法。