![](/img/trans.png)
[英]I cannot figure out why I have this error: ConcurrentModificationException
[英]Cannot figure out why it throws ConcurrentModificationException
我有ConcurrentModificationException,不知道为什么。 我知道尝试使用for循环遍历列表并删除循环块内的元素是一个坏主意,并且可能引发此类异常,但是我不知道如何解决此问题。
private static final List<Integer> originalList = new ArrayList<>();
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
originalList.add(i);
}
final int MAX_GROUP_SIZE = 5;
int partitionSize = 4;
List<List<Integer>> partitions = new LinkedList<>();
for (int i = 0; i < originalList.size(); i += partitionSize) {
partitions.add(originalList.subList(i,
Math.min(i + partitionSize, originalList.size())));
}
int lastGroupSize = partitions.get(partitions.size() - 1).size();
if (lastGroupSize < partitionSize && partitions.size() > lastGroupSize){
List<Integer> lastGroup = partitions.remove(partitions.size() - 1);
for (int i = 0; i < lastGroupSize; i++) {
partitions.get(i).add(lastGroup.get(i));
}
}
System.out.println("GROUPS: " + partitions.size());
printGroups(new LinkedList<>(partitions));
}
问题在于您对subList()
调用不会创建新列表。 正如javadoc所说:
返回此列表中指定的fromIndex(包括)和toIndex(不包括)之间的视图 。
Javadoc还说:
如果后备列表(即此列表)以结构方式(而不是通过返回的列表)进行了修改 ,则此方法返回的列表的语义将变得不确定。
当您调用partitions.get(i).add(...)
,您正在结构上修改 originalList
,从而导致错误。
我不认为您打算这样做,因此要解决此问题,您只需要确保子列表独立于原始列表(即副本)即可,这很容易做到:
new ArrayList<>(originalList.subList(...))
使用ArrayList(Collection)
构造函数将创建子列表的副本。
因此,更改此语句:
partitions.add(originalList.subList(i,
Math.min(i + partitionSize, originalList.size())));
对此:
partitions.add(new ArrayList<>(originalList.subList(i,
Math.min(i + partitionSize, originalList.size()))));
绝对不要迭代列表并执行更新操作(更新意味着添加或删除元素)。 这是灾难的秘诀。
为了解决此问题,有以下三种可能的方案:
1)复制列表,遍历副本,然后从原始列表中删除。
for (var number : new ArrayList<>(original)) {
if (element > 10) {
original.remove(element);
}
}
2)使用流
List<Integer> filtered = original.stream()
.filter(i -> i > 10)
.collect(Collectors.toList());
3)使用迭代器遍历列表
Iterator<Integer> iterator = original.iterator();
while (iterator.hasNex()) {
Integer number = iterator.next();
if (number > 10) {
iterator.remove();
}
}
我个人更喜欢流。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.