我正在使用Iteratot迭代ArrayList的元素。重复迭代我最后在ArrayList中添加了一个元素。但是收到错误:ConcurrentModificationException。
如果我将ArrayList更改为Set并尝试在迭代期间在set中添加元素,则不会抛出错误
Test.java
class Test {
public static void main() {
ArrayList<Integer> al = new ArrayList<Integer>();
al.add(20);
al.add(30);
al.add(40);
Iterator<Integer> it = marks.iterator();
while (it.hasNext()) {
int value = it.next();
if (value == 40) al.add(50);
}
}
}
Test2.java
class Test2 {
public static void main() {
Set<Integer> marks = new HashSet<>();
marks.add(20);
marks.add(30);
marks.add(40);
Iterator<Integer> it = marks.iterator();
while (it.hasNext()) {
int value = it.next();
if (value == 40) marks.add(50);
}
}
}
答案 0 :(得分:4)
可能有一个更好的解决方案,但这个解决方案也是如此。在循环结束后,使用第二个列表,然后将其添加到原始列表中。
主要强>
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Integer> al = new ArrayList<Integer>();
List<Integer> toAdd = new ArrayList<Integer>();
int stepSize = 10;
al.add(20);
al.add(30);
al.add(40);
Iterator<Integer> it = al.iterator();
while (it.hasNext()) {
int value = it.next();
if (value == al.get(al.size() - 1)){
toAdd.add(value + stepSize);
}
}
// Add all elements
al.addAll(toAdd);
// Print
al.forEach(System.out::println);
}
}
如果你只想根据最后一个值附加一个元素,就像在你的例子中一样,你也可以等到循环完成(如果你仍然需要它)并尝试添加它是这样的:
al.add(al.get(al.size() - 1) + stepSize);
<强>输出强>
20
30
40
50
答案 1 :(得分:1)
仅凭ConcurrentModificationException
HashSet
获得HashSet
仅仅是侥幸。这种侥幸的原因是你碰巧在循环的 last 迭代中添加了元素。
这远非保证发生,因为ConcurrentModificationException
没有排序保证。尝试在列表中添加或删除更多元素,您会发现最终能够获得40
,因为HashSet
不会是列表中的最后一个元素。
重现这一点的最简单方法是只使用一个元素(从那时起HashSet<Integer> hashSet = new HashSet<>();
hashSet.add(1);
for (int i : hashSet) {
hashSet.add(2);
}
的排序已知):
ConcurrentModificationException
这不会抛出ArrayList<Integer> list = new ArrayList<>();
list.add(1);
for (int i : list) {
list.add(2);
}
。
ConcurrentModificationException
此将抛出HashSet
。
关于在最后一次迭代中添加abstract class HashIterator {
// ...
public final boolean hasNext() {
return next != null;
}
// ...
}
时没有得到异常的原因,
查看HashSet.iterator()
返回的迭代器的源代码:
hasNext()
因此,next
值是基于 final Node<K,V> nextNode() {
Node<K,V>[] t;
Node<K,V> e = next;
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (e == null)
throw new NoSuchElementException();
if ((next = (current = e).next) == null && (t = table) != null) {
do {} while (index < t.length && (next = t[index++]) == null);
// ^ Here
}
return e;
}
预先计算的;这在代码中设置得稍低:
hasNext
因此,当确定迭代的前一个元素时,确定Iterator it = marks.iterator();
while (it.hasNext()) {
int value = it.next();
if (value == 40)
marks.add(50);
}
的值。
因为您的代码是:
hasNext()
在循环迭代之后调用next
,其中添加了元素;但在调用it.next()
之前add
被设置为空 - 在调用hasNext()
之前 - 因此ConcurrentModificationException
将返回false,并且循环退出时不会hasNext()
另一方面,iterator of ArrayList
使用基础列表的大小来确定 public boolean hasNext() {
return cursor != size;
// ^ current position of the iterator
// ^ current size of the list
}
的返回值:
hasNext()
因此,就增加(或减少)基础列表的大小而言,此值是“实时”的。因此,next()
在添加值后将返回true;因此调用了next()
。但 public E next() {
checkForComodification();
// ...
做的第一件事就是检查编纂:
ConcurrentModificationException
因此检测到更改,并抛出ConcurrentModificationException
。
请注意,如果您在最后一次迭代中修改了,那么将获得ArrayList
<div class="row" *ngFor="let contact of contacts">
<!-- Here I want to loop 4 of the contacts before rendering a new row -->
<div class="col-md-3">
<contact-card [contact]="contact"></contact-card>
</div>
</div>
,如果您要添加并删除一个元素(或者更确切地说,添加和删除相同数量的元素,以便之后列表的大小相同)。
答案 2 :(得分:0)