java中的方法List.of(E... elements)
返回的列表确实返回了一个不可变的列表,但是通过查看创建的列表,这一点根本看不见。创建的列表只是抛出一个异常,而不是完全不显示更改列表的可能性。我的观点是,List.of(E... elements)
应该返回一个ImmutableList
,即extends List
。这样,用户就可以决定他是否愿意展示这个不变的事实。
但是我没有发现有人在抱怨或者提出其他的解决方案。即使是番石榴和ApacheCommons默认情况下也不会这样做。只有番石榴才有可能创建它(尽管使用了大量代码):
List<String> list = new ArrayList<String>(Arrays.asList("one", "two", "three"));
ImmutableList<String> unmodifiableList = ImmutableList.<String>builder().addAll(list).build();
但是即使这个类也有一个(不推荐的) add
和remove
方法。
有人能告诉我为什么没有人关心这个(看似根本的)问题吗?
发布于 2019-09-13 15:18:26
这并不是说没有人在乎,而是因为这是一个相当微妙的问题。
不存在“不可变”集合接口家族的最初原因是由于对界面增殖的关注。可能存在的接口不仅是不可变的,而且是同步的和运行时类型的检查集合,还有可以设置但不添加或删除元素的集合(例如,Arrays.asList或可以从其中删除但不能添加元素的集合(例如,Map.keySet )。
但也可以说,不变性是如此重要,以至于它应该是特殊的大小写,而且即使没有对所有其他特性的支持,也应该支持它的类型层次结构。当然可以。
最初的建议是让ImmutableList
接口扩展List
,如
ImmutableList <:List <:集合
(其中<:
的意思是“是”的一个子类型。)
当然可以这样做,但是ImmutableList
将继承List
中的所有方法,包括所有的mutator方法。必须对它们做一些事情;子接口不能从超级接口“继承”方法。最好的方法是指定这些方法抛出异常,提供这样做的默认实现,并可能将这些方法标记为废弃,以便程序员在编译时得到警告。
这很管用,但没什么用。不能保证这样一个接口的实现是不可变的。恶意或错误的实现可以覆盖mutator方法,也可以简单地添加更多变异状态的方法。任何使用ImmutableList
的程序都不能假设列表实际上是不可变的。
这方面的一个变化是使ImmutableList
成为类而不是接口,定义它的mutator方法来抛出异常,使它们成为最终的,并且不提供公共构造函数,以限制实现。事实上,这正是番石榴的ImmutableList
所做的。如果您信任番石榴开发人员(我认为他们很有名),那么如果您有一个番石榴ImmutableList
实例,您就可以确信它实际上是不可变的。例如,您可以将它存储在一个字段中,因为您知道它不会意外地从您的下面改变。但这也意味着您不能添加另一个ImmutableList
实现,至少在不修改番石榴的情况下是不可能的。
这种方法没有解决的一个问题是通过向上转换“擦除”不可变性。许多现有的API使用Collection
或Iterable
类型的参数来定义方法。如果要将一个ImmutableList
传递给这样一个方法,它将丢失表示列表不可变的类型信息。为了从中受益,您必须在任何地方都添加不可变的风味重载。或者,您可以在任何地方添加instanceof
检查。两者都很混乱。
(注意,JDK的List.copyOf
作为另一种选择,人们可能会争辩说,我们不希望ImmutableList
成为List
的子接口,我们希望它成为一个超级接口:
列表<:ImmutableList
通过这种方式,ImmutableList
不必指定所有这些mutator方法都抛出异常,它们将根本不存在于接口中。这很好,只是这个模型完全错了。因为ArrayList
是List
,这意味着ArrayList
也是ImmutableList
,这显然是荒谬的。问题是,“不可变”意味着对子类型的限制,这在继承层次结构中是做不到的。相反,它需要被重命名,以允许功能随着层次结构的下降而增加,例如,
列表<:ReadableList
这更准确。然而,ReadableList
与ImmutableList
完全不同。
最后,我们还没有考虑到一些语义问题。一个是不变的还是不可修改的。Java有支持不可修改性的API,例如:
List<String> alist = new ArrayList<>(...);
??? ulist = Collections.unmodifiableList(alist);
ulist
的类型应该是什么?它不是一成不变的,因为如果有人更改支持列表alist
,它就会改变。现在考虑:
???<String[]> arlist = List.of(new String[] { ... }, new String[] { ... });
这种类型应该是什么?它当然不是不可变的,因为它包含数组,而且数组总是可变的。因此,说List.of
返回不可变的东西是否合理,这一点一点也不清楚。
https://stackoverflow.com/questions/57921251
复制相似问题