我使用subList Method.Now创建了一个新的ArrayList,当我尝试使用retainAll执行交集操作时抛出以下异常
retainAll()方法适用于以下代码
List<Integer> arrNums1 = new ArrayList<Integer>();
arrNums1.add(1);
arrNums1.add(2);
arrNums1.add(3);
List<Integer> arrNums2 = arrNums1.subList(0, 1);
arrNums2.retainAll(arrNums1);
但是当我尝试将retainAll应用于Below代码时,它会生成Exception as Below
Java代码
public class Generics1
{
public static void main(String[] args)
{
List<Fruits> arrFruits = new ArrayList<Fruits>();
Fruits objApple = new Apple();
Fruits objOrange = new Orange();
Fruits objMango = new Mango();
arrFruits.add(objApple);
arrFruits.add(objOrange);
arrFruits.add(objMango);
List<Fruits> arrNewFruits = arrFruits.subList(0, 1);
System.out.println(arrFruits.retainAll(arrNewFruits));
}
}
class Fruits {}
class Apple extends Fruits {}
class Orange extends Fruits {}
class Mango extends Fruits {}
错误
答案 0 :(得分:7)
使用List#subList()时:
返回指定fromIndex(包含)和toIndex(不包括)之间此列表部分的视图。(如果fromIndex和toIndex相等,则返回的列表为空。)返回的列表为此列表支持,因此返回列表中的非结构更改将反映在此列表中,反之亦然。返回的列表支持此列表支持的所有可选列表操作。
您可以改变其中的元素,但不能更改列表的结构。
该文件进一步说:
如果支持列表(即此列表)在结构上以除返回列表之外的任何方式进行修改,则此方法返回的列表的语义将变为未定义。(结构修改是那些更改此列表的大小,或以其他方式扰乱它,使得正在进行的迭代可能会产生不正确的结果。)
retainAll()
函数使用迭代器删除非相交值,这会导致ConcurrentModificationException
。请注意documenation所说的内容:
请注意,此异常并不总是表示某个对象已被另一个线程同时修改。如果单个线程发出一系列违反对象契约的方法调用,则该对象可能会抛出此异常。
制作List
的副本,然后执行retainAll()
:
List<Fruits> arrNewFruits = new ArrayList<>(arrFruits.subList(0, 1));
答案 1 :(得分:3)
在您的两个代码示例中,您有相反的大列表和子列表。
当您在子列表上调用retainAll()
时,不会进行任何修改。
这是因为子列表中的每个元素都在大列表中。
如果未进行任何修改,则不会抛出ConcurrentModificationException
。
您使用整数列表执行此操作。
如果您撤销订单并在大清单上调用retainAll()
,它将会发生变异。
这是因为并非大型列表中的每个项目都在子列表中。
从大列表中删除元素时,会抛出ConcurrentModificationException
。
这是因为在迭代时不能改变列表。
您可以使用水果列表执行此操作。
迭代发生在retainAll()
方法中。
在您的代码中,list参数恰好引用了正被修改的相同列表。
这是因为List.subList()
的工作方式:
返回指定fromIndex(包含)和toIndex(独占)之间此列表部分的视图。 (如果fromIndex和toIndex相等,则返回的列表为空。)返回的列表由此列表支持,因此返回列表中的非结构更改将反映在此列表中,反之亦然。
长话短说:
您不会遇到异常如果您将代码更改为:
System.out.println(arrNewFruits.retainAll(arrFruits));
更重要的是:
如果在迭代其中一个列表时有可能修改任一列表,则需要从子列表中创建一个新列表。
您可以从子列表中创建一个新列表,如下所示:
List<Foo> freshList = new ArrayList<Foo>(bigList.subList(0,2));
现在你可以迭代并改变你心中的内容!
这是ArrayList.retainAll()
的实现,您可以在其中查找迭代。
答案 2 :(得分:2)
问题是arrNewFruits
实际上只是arrFruits
的一部分的逻辑视图。 1 为了避免错误,您需要创建一个独立的列表: / p>
List<Fruits> arrNewFruits = new ArrayList<>(arrFruits.subList(0, 1));
1 这就是为什么你可以通过在clear()
上调用subList()
来删除部分列表的原因 - 在另一个中可以看到对一个列表的更改。