首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么Java中的List.of()不返回一个类型化的不可变列表?

为什么Java中的List.of()不返回一个类型化的不可变列表?
EN

Stack Overflow用户
提问于 2019-09-13 09:49:20
回答 3查看 7.4K关注 0票数 10

java中的方法List.of(E... elements)返回的列表确实返回了一个不可变的列表,但是通过查看创建的列表,这一点根本看不见。创建的列表只是抛出一个异常,而不是完全不显示更改列表的可能性。我的观点是,List.of(E... elements)应该返回一个ImmutableList,即extends List。这样,用户就可以决定他是否愿意展示这个不变的事实。

但是我没有发现有人在抱怨或者提出其他的解决方案。即使是番石榴和ApacheCommons默认情况下也不会这样做。只有番石榴才有可能创建它(尽管使用了大量代码):

代码语言:javascript
运行
复制
List<String> list = new ArrayList<String>(Arrays.asList("one", "two", "three"));
ImmutableList<String> unmodifiableList = ImmutableList.<String>builder().addAll(list).build();

但是即使这个类也有一个(不推荐的) addremove方法。

有人能告诉我为什么没有人关心这个(看似根本的)问题吗?

EN

Stack Overflow用户

回答已采纳

发布于 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使用CollectionIterable类型的参数来定义方法。如果要将一个ImmutableList传递给这样一个方法,它将丢失表示列表不可变的类型信息。为了从中受益,您必须在任何地方都添加不可变的风味重载。或者,您可以在任何地方添加instanceof检查。两者都很混乱。

(注意,JDK的List.copyOf

作为另一种选择,人们可能会争辩说,我们不希望ImmutableList成为List的子接口,我们希望它成为一个超级接口:

列表<:ImmutableList

通过这种方式,ImmutableList不必指定所有这些mutator方法都抛出异常,它们将根本不存在于接口中。这很好,只是这个模型完全错了。因为ArrayListList,这意味着ArrayList也是ImmutableList,这显然是荒谬的。问题是,“不可变”意味着对子类型的限制,这在继承层次结构中是做不到的。相反,它需要被重命名,以允许功能随着层次结构的下降而增加,例如,

列表<:ReadableList

这更准确。然而,ReadableListImmutableList完全不同。

最后,我们还没有考虑到一些语义问题。一个是不变的还是不可修改的。Java有支持不可修改性的API,例如:

代码语言:javascript
运行
复制
List<String> alist = new ArrayList<>(...);
??? ulist = Collections.unmodifiableList(alist);

ulist的类型应该是什么?它不是一成不变的,因为如果有人更改支持列表alist,它就会改变。现在考虑:

代码语言:javascript
运行
复制
???<String[]> arlist = List.of(new String[] { ... }, new String[] { ... });

这种类型应该是什么?它当然不是不可变的,因为它包含数组,而且数组总是可变的。因此,说List.of返回不可变的东西是否合理,这一点一点也不清楚。

票数 24
EN
查看全部 3 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57921251

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档