如您所知,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)clearremove(Object o)该方法未标记为可选,但也可以抛出不可变集合。removeAll(Collection<?> c)retainAll(Collection<?> c)removeIf(Predicate<? super E> filter)UnsupportedOperationExceptionList:对列表中的索引进行操作、、、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)?: