Arrays.asList是否违反Liskov替代原则?

Gon*_*n I 3 java arrays liskov-substitution-principle list

Arrays.asList(..)返回数组的列表包装器。此包装具有固定的大小,并直接由数组支持,因此,对add()或试图修改列表的其他函数的调用将引发UnsupportedOperationException。

从堆栈溢出中的问题可以明显看出,开发人员常常对此感到惊讶。

但是,根据Liskov替换原理(LSP),List接口具有add()方法,该方法对于List的所有派生类都应该正常工作

Arrays.asList()返回的类型是否是违反Liskov替代原理的示例?

das*_*ght 5

严格来说,是因为LSP没有可选接口成员的概念:方法要么是接口的一部分,要么不是接口的一部分。

但是,当Java类库将某些接口方法指定为可选时,它明确允许违反LSP。List<T>.add()是一种这样的方法。其他变异方法(addAllremove等)也标记为可选。

本质上,Java库的设计人员采用了一种捷径:他们没有为可变列表创建单独的接口(扩展了只读列表),而是将其指定为“可选”操作。而且,它们还没有为您提供测试list实例是否为只读的方法,因此您唯一的选择是捕获运行时异常,这是一个非常糟糕的主意。这意味着您必须跟踪列表的来源,并且仅在100%确定列表来源时才执行可选操作。

  • @user889742 对 - LSP 没有“可选操作”的概念,一切都是完美的二进制。Java 库设计者走了一条捷径,没有为只读列表定义单独的接口,从而造成了可选操作的混乱。 (2认同)

And*_*ner 5

我认为这并不违反LSP。

LSP 说实现给定接口的类的所有实例都可以互换使用。

List.add(和其他变异方法)的文档清楚地说明UnsupportedOperationException了该方法的实现可能会抛出 。

投掷

UnsupportedOperationException - 如果此列表不支持添加操作

因此,如果您要对List来自未知来源的的实例调用此方法,则需要处理add抛出UnsupportedOperationException.

如果不这样做,则说明您没有正确使用 API。


这并不是说我喜欢这个设计。我认为尝试调用该方法是检测实例不支持任何给定方法的唯一方法这一事实是垃圾。我的意思是,哎呀,给我们一个isAddSupported()方法(或类似的方法)。

我只是没有看到以下记录的行为可能违反 LSP。