他们为什么决定使接口具有“可选操作”。 [英] Why did they decide to make interfaces have "Optional Operations"

查看:87
本文介绍了他们为什么决定使接口具有“可选操作”。的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

ImmutableSet 实施设置界面。对 ImmutableSet 没有意义的函数现在称为 Set 的可选操作。我假设这样的情况。所以 ImmutableSet 现在为许多可选操作抛出 UnsupportedOperationException



<这对我来说似乎倒退了。我被告知接口是一个契约,因此您可以在不同的实现中使用强制功能。可选操作的方法似乎从根本上改变(矛盾?)接口的意图。今天实现这个我将把 Set 接口分成两个接口:一个用于不可变操作,另一个用于扩展这些操作用于mutator。 (非常快,脱掉袖带解决方案)



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

解决方案

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操作。它们需要一个新的核心接口和一个新的迭代器。



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



现在我们最多有二十个接口和五个迭代器,而且几乎可以肯定仍有集合在实践中产生的,不适合任何接口。例如,Map返回的集合视图是自然删除集合。此外,有些集合会根据它们的值拒绝某些元素,所以我们仍然没有消除运行时异常。



当所有的事情都说完了我们认为通过提供一组可以引发运行时异常的非常小的核心接口来回避整个问题是一个合理的工程折衷方案。


简而言之,使用可选操作的 Set 这样的接口是为了防止所需的不同接口数量呈指数级增长。它不像不可变和可变那么简单。然后,Guava的 ImmutableSet 必须实现 Set 才能与使用 Set <的所有其他代码互操作/ code>秒。这不是理想的,但实际上没有更好的方法。


ImmutableSet implements the Set interface. The functions that don't make sense to an ImmutableSet are now called "Optional Operations" for Set. I assume for situations like this. So ImmutableSet now throws an UnsupportedOperationException for many Optional Operations.

This seems backwards to me. I was taught that an Interface was a contract so that you could use impose functionality across different implementations. The approach of Optional Operations seem to fundamentally change(contradict?) what Interfaces are meant to do. Implementing this today I would have the Set Interface broken into two interfaces: one for one for immutable operations and a second extending those operations for mutators. (Very quick, off the cuff solution)

I understand that technology changes. I'm not saying It should be done one way or another. My question is, does this change reflect a change in some underlying philosophy for Java? Is it just more of a bandaid to make things backwards compatible? Did I have an incomplete understanding of Interfaces?

解决方案

The Java Collections API Design FAQ answers this question in detail:

Q: Why don't you support immutability directly in the core collection interfaces so that you can do away with optional operations (and UnsupportedOperationException)?

A: This is the most controversial design decision in the whole API. Clearly, static (compile time) type checking is highly desirable, and is the norm in Java. We would have supported it if we believed it were feasible. Unfortunately, attempts to achieve this goal cause an explosion in the size of the interface hierarchy, and do not succeed in eliminating the need for runtime exceptions (though they reduce it substantially).

Doug Lea, who wrote a popular Java collections package that did reflect mutability distinctions in its interface hierarchy, no longer believes it is a viable approach, based on user experience with his collections package. In his words (from personal correspondence) "Much as it pains me to say it, strong static typing does not work for collection interfaces in Java."

To illustrate the problem in gory detail, suppose you want to add the notion of modifiability to the Hierarchy. You need four new interfaces: ModifiableCollection, ModifiableSet, ModifiableList, and ModifiableMap. What was previously a simple hierarchy is now a messy heterarchy. Also, you need a new Iterator interface for use with unmodifiable Collections, that does not contain the remove operation. Now can you do away with UnsupportedOperationException? Unfortunately not.

Consider arrays. They implement most of the List operations, but not remove and add. They are "fixed-size" Lists. If you want to capture this notion in the hierarchy, you have to add two new interfaces: VariableSizeList and VariableSizeMap. You don't have to add VariableSizeCollection and VariableSizeSet, because they'd be identical to ModifiableCollection and ModifiableSet, but you might choose to add them anyway for consistency's sake. Also, you need a new variety of ListIterator that doesn't support the add and remove operations, to go along with unmodifiable List. Now we're up to ten or twelve interfaces, plus two new Iterator interfaces, instead of our original four. Are we done? No.

Consider logs (such as error logs, audit logs and journals for recoverable data objects). They are natural append-only sequences, that support all of the List operations except for remove and set (replace). They require a new core interface, and a new iterator.

And what about immutable Collections, as opposed to unmodifiable ones? (i.e., Collections that cannot be changed by the client AND will never change for any other reason). Many argue that this is the most important distinction of all, because it allows multiple threads to access a collection concurrently without the need for synchronization. Adding this support to the type hierarchy requires four more interfaces.

Now we're up to twenty or so interfaces and five iterators, and it's almost certain that there are still collections arising in practice that don't fit cleanly into any of the interfaces. For example, the collection-views returned by Map are natural delete-only collections. Also, there are collections that will reject certain elements on the basis of their value, so we still haven't done away with runtime exceptions.

When all was said and done, we felt that it was a sound engineering compromise to sidestep the whole issue by providing a very small set of core interfaces that can throw a runtime exception.

In short, having interfaces like Set with optional operations was done to prevent an exponential explosion in the number of different interfaces needed. It is not as simple as just "immutable" and "mutable". Guava's ImmutableSet then had to implement Set to be interoperable with all other code which uses Sets. It's not ideal but there is really no better way to do it.

这篇关于他们为什么决定使接口具有“可选操作”。的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆