Joh*_*uer 2 java collections apache-commons guava
List.of(E... elements)java中的方法返回的列表确实返回了一个不可变的列表,但是通过查看所创建的列表根本看不到该列表。创建的列表只是抛出一个异常,而不是根本没有显示更改列表的可能性。我的意思是,那List.of(E... elements)应该返回一个ImmutableListthat extends List。这样,用户可以决定他是否愿意显示这种不变性的事实。但是我没有发现有人抱怨或显示其他解决方案。默认情况下,甚至Guava和Apache Commons也不会这样做。只有Guava才有可能创建它(尽管有很多代码):
List<String> list = new ArrayList<String>(Arrays.asList("one", "two", "three"));
ImmutableList<String> unmodifiableList = ImmutableList.<String>builder().addAll(list).build();
Run Code Online (Sandbox Code Playgroud)
但是,即使此类也具有(不建议使用)add和remove方法。
谁能告诉我为什么没人关心这个(看似基本的)问题?
不是没有人在乎;这是一个相当微妙的问题。
没有一个“不可变的”集合接口家族的最初原因是由于对接口扩散的担忧。可能不仅存在用于不变性的接口,而且可能存在同步的和运行时类型检查过的集合,以及可能设置了元素但未添加或删除的集合(例如Arrays.asList)或可以删除但不添加元素的集合。 (例如Map.keySet)。
但是也可以说,不变性是如此重要,以至于应采用特殊情况,并且即使不支持所有其他特征,类型层次结构中也应对此提供支持。很公平。
最初的建议是有一个ImmutableList接口extend List,如
ImmutableList <:列表<:集合
(其中<:“是”的子类型。)
当然可以做到这一点,但是ImmutableList可以继承的所有方法List,包括所有的mutator方法。他们将不得不做些事情。子接口无法从超级接口“取消继承”方法。最好的办法是指定这些方法抛出异常,提供默认的实现,并标记方法已弃用,以便程序员在编译时得到警告。
This works, but it doesn't help much. An implementation of such an interface cannot be guaranteed to be immutable at all. A malicious or buggy implementation could override the mutator methods, or it could simply add more methods that mutate the state. Any programs that used ImmutableList couldn't make any assumptions that the list was, in fact, immutable.
A variation on this is to make ImmutableList be a class instead of an interface, to define its mutator methods to throw exceptions, to make them final, and to provide no public constructors, in order to restrict implementations. In fact, this is exactly what Guava's ImmutableList has done. If you trust the Guava developers (I think they're pretty reputable) then if you have a Guava ImmutableList instance, you're assured that it is in fact immutable. For example, you could store it in a field with the knowledge that it won't change out from under you unexpectedly. But this also means that you can't add another ImmutableList implementation, at least not without modifying Guava.
A problem that isn't solved by this approach is the "scrubbing" of immutability by upcasting. A lot of existing APIs define methods with parameters of type Collection or Iterable. If you were to pass an ImmutableList to such a method, it would lose the type information indicating that the list is immutable. To benefit from this, you'd have to add immutable-flavored overloads everywhere. Or, you could add instanceof checks everywhere. Both are pretty messy.
(Note that the JDK's List.copyOf sidesteps this problem. Even though there are no immutable types, it checks the implementation before making a copy, and avoids making copies unnecessarily. Thus, callers can use List.copyOf to make defensive copies with impunity.)
As an alternative, one might argue that we don't want ImmutableList to be a sub-interface of List, we want it to be a super-interface:
List <: ImmutableList
This way, instead of ImmutableList having to specify that all those mutator methods throw exceptions, they wouldn't be present in the interface at all. This is nice, except that this model is completely wrong. Since ArrayList is a List, that means ArrayList is also an ImmutableList, which is clearly nonsensical. The problem is that "immutable" implies a restriction on subtypes, which can't be done in an inheritance hierarchy. Instead, it would need to be renamed to allow capabilities to be added as one goes down the hierarchy, for example,
List <: ReadableList
which is more accurate. However, ReadableList is altogether a different thing from an ImmutableList.
Finally, there are a bunch of semantic issues that we haven't considered. One concerns immutability vs. unmodifiability. Java has APIs that support unmodifiability, for example:
List<String> alist = new ArrayList<>(...);
??? ulist = Collections.unmodifiableList(alist);
Run Code Online (Sandbox Code Playgroud)
What should the type of ulist be? It's not immutable, since it will change if somebody changes the backing list alist. Now consider:
???<String[]> arlist = List.of(new String[] { ... }, new String[] { ... });
Run Code Online (Sandbox Code Playgroud)
What should the type be? It's certainly not immutable, as it contains arrays, and arrays are always mutable. Thus it's not at all clear that it would be reasonable to say that List.of returns something immutable.
| 归档时间: |
|
| 查看次数: |
146 次 |
| 最近记录: |