如您所知,List.of
它Java
返回一个不可变的列表。这不是来自 a 的糟糕语言设计吗Liskov Substitution Principle
?
维基百科的定义:
如果 S 是 T 的子类型,则程序中类型 T 的对象可以用类型 S 的对象替换,而无需对该程序所需的属性进行任何更改。
毕竟,如果有某种方法:
void addElement(List<String> list){
list.add("Liskov");
}
那么如果将通过创建的 List 传递给该方法,则会抛出异常List.of
,这与方法相矛盾LSP
。当然,尽管整件事solid
只是一组建议。
如果你认为Kotlin
,那么在我看来,就语言设计而言,他们做得更正确。我们创建了集合List
(不可变)和MutableList
.
还是我还是有误解LSP
?
由于问题中所述的原因,通常具有不可变列表和集合以及其他受约束的类型实现
Arrays.asList
可以被视为违反 SOLID 中的纯LSP 原则。此外,使用工厂方法获取的列表List.of
也不能包含null
值。对于线程安全集合的不同实现,行为也可能有所不同但是,不同实现的不同行为的可能性已被正式记录,特别是在相应接口的文档中
List
/Collection
它指出导致集合及其内容发生更改的所有操作都是可选的,也就是说,它们可以,但不需要抛出异常UnsupportedOperationException
:Java 8
Collection
另外,对于列表,在某些实现中可以禁止重复项的存在,这也可以被视为某种允许违反LSP 原则的行为:
可选修改操作:
Collection
:add(E e)
,,,,,,, ;addAll(Collection<? extends E> c)
clear
remove(Object o)
该方法未标记为可选,但也可以抛出不可变集合。removeAll(Collection<?> c)
retainAll(Collection<?> c)
removeIf(Predicate<? super E> filter)
UnsupportedOperationException
List
:对列表中的索引进行操作、、、add(int index, E element)
和默认实现,addAll(int index, Collection<? extends E> c)
remove(int index)
set(int index, E element)
replaceAll(UnaryOperator<E> operator)
sort(Comparator<? super E> c)
Set
:与父界面相同的操作Collection
也就是说,我们可以假设接口合同中存在
Collection
/List
类似的关于其可选更改的条款,并在一般情况下抛出指定的异常,使我们能够避免违反 LSP 原则。主要SO的相关问题:
Arrays.asList
违反里氏替换原则? 2016年Collections.unmodifiableXXX
违反LSP? 2014年Kotlin 的创建要晚得多,显然它的开发人员并不害怕“膨胀”接口的数量。 Java 故意做出了某种妥协,文档Java Collections API Design FAQ::Core Interfaces - General Questions
为什么不在核心集合接口中直接支持不变性,这样就可以取消可选操作(和
UnsupportedOperationException
)?: