为什么 Collections.sort(List) 在 Java 8 中与 CopyOnWriteArrayList 一起工作,但在 Java 7 中却不工作?

2022-09-04 01:42:57

我可以使用以下代码和Java 8对用户列表进行排序而不会出现任何问题:

CopyOnWriteArrayList<User> allCurrentLoginnedUsersList = new CopyOnWriteArrayList<>(); 
Collections.sort(allCurrentLoginnedUsersList);

现在,我改用了Java 7,在eclipse上我没有看到任何错误。但是现在,在Java 7下运行时,我得到了这个错误:

java.lang.UnsupportedOperationException
    at java.util.concurrent.CopyOnWriteArrayList$COWIterator.set(CopyOnWriteArrayList.java:1049)
    at java.util.Collections.sort(Collections.java:221)
    at com.fluent.User.sortAllCurrentLoginnedUsers(User.java:446)

如何解决?


答案 1

Java 7(以及Java 8的早期版本)和Java 8u20在工作方式上发生了变化(如Holger所指出的,问题8032636)。Collections.sort


Java 7 Collections.sort(list, c) 指定:

此实现将指定的列表转储到数组中,对数组进行排序,并循环访问列表,从数组中的相应位置重置每个元素。这避免了尝试对链接列表进行排序而导致的 n² log(n) 性能。

查看代码,这是通过从列表中获取 a 来完成的。但是,listIterator() 方法声明返回的迭代器不支持该操作:ListIteratorCopyOnWriteArrayListset

返回的迭代器提供构造迭代器时列表状态的快照。遍历迭代器时不需要同步。迭代器不支持删除设置添加方法

这解释了使用 Java 7 运行代码时遇到的错误。作为一种解决方法,您可以参考此问题,其中的答案是将列表的内容转储到数组中,对数组进行排序并将元素放回列表中。


在Java 8中,Collections.sort(list,c)更改了实现:

此实现遵从使用指定列表和比较器的方法。List.sort(Comparator)

新方法CopyOnWriteArrayList.sort(c)(在Java 8中引入)不使用列表迭代器,因此它可以正常工作。


答案 2

Collections.sort(),在 Java 7(以及 Java 8 的早期版本)中使用列表迭代器来修改列表。但是CopyOnWriteArrayList的迭代器被明确记录为不支持此操作。set()

如何解决?将 你转换为常规 ArrayList 或数组,对其进行排序,然后清除 CopyOnWriteArrayList,然后用排序的列表再次填充它。CopyOnWriteArrayList

我强烈建议使用 和 来使您的比较器更简单。Integer.compare()Boolean.compare()