我使用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);
Run Code Online (Sandbox Code Playgroud)
但是当我尝试将retainAll应用于Below代码时,它会生成Exception,如下所示
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 {}
Run Code Online (Sandbox Code Playgroud)
错误

返回指定fromIndex(包含)和toIndex(独占)之间此列表部分的视图.(如果fromIndex和toIndex相等,则返回的列表为空.)返回的列表由此列表支持,因此返回列表中的非结构更改将反映在此列表中,反之亦然.返回的列表支持此列表支持的所有可选列表操作.
您可以改变其中的元素,但不能更改列表的结构.
该文件进一步说:
如果支持列表(即此列表)在结构上以除返回列表之外的任何方式进行修改,则此方法返回的列表的语义将变为未定义.(结构修改是那些改变了这个列表的大小,或以其他方式扰乱它的方式,正在进行的迭代可能会产生不正确的结果.)
该retainAll()函数使用迭代器来删除非相交的值,这会导致ConcurrentModificationException.请注意文档说的内容:
请注意,此异常并不总是表示某个对象已被另一个线程同时修改.如果单个线程发出违反对象合同的一系列方法调用,则该对象可能会抛出此异常.
制作一份副本,List然后执行retainAll():
List<Fruits> arrNewFruits = new ArrayList<>(arrFruits.subList(0, 1));
Run Code Online (Sandbox Code Playgroud)
在您的两个代码示例中,您有大列表和子列表,顺序相反。
当您调用retainAll()子列表时,不会发生任何修改。
这是因为子列表中的每个元素都在大列表中。
如果没有发生修改,则ConcurrentModificationException不会抛出 no 。
您可以使用Integers列表执行上面的操作。
如果你颠倒顺序并retainAll()在大列表上调用,它就会发生变化。
这是因为并非大列表中的每个项目都在子列表中。
当您从大列表中删除一个元素时,ConcurrentModificationException会抛出 a 。
这是因为您无法在迭代列表时改变列表。
您可以在上面使用Fruits列表执行此操作。
迭代发生在retainAll()方法中。
在您的代码中,列表参数恰好引用正在修改的同一列表。
这是因为List.subList()工作方式:
返回此列表中指定的 fromIndex(包含)和 toIndex(不包含)之间的部分的视图。(如果 fromIndex 和 toIndex 相等,则返回的列表为空。)返回的列表受此列表支持,因此返回列表中的非结构性更改会反映在此列表中,反之亦然。
长话短说:
如果将代码更改为以下内容,则不会出现异常:
System.out.println(arrNewFruits.retainAll(arrFruits));
Run Code Online (Sandbox Code Playgroud)
更重要的是:
如果在迭代其中一个列表时任一列表有可能被修改,您需要从子列表创建一个新列表。
您可以从子列表创建一个新列表,如下所示:
List<Foo> freshList = new ArrayList<Foo>(bigList.subList(0,2));
Run Code Online (Sandbox Code Playgroud)
现在您可以随心所欲地迭代和变异!
这是 的实现ArrayList.retainAll(),您可以在其中查找迭代。
| 归档时间: |
|
| 查看次数: |
615 次 |
| 最近记录: |