참고 : Iterator#remove()
방법을 알고 있습니다.
왜 ‘다음 코드 샘플에서는 이해가 안 List.remove
의 main
방법은 발생 ConcurrentModificationException
하지만, 하지 에 remove
방법.
public class RemoveListElementDemo {
private static final List<Integer> integerList;
static {
integerList = new ArrayList<Integer>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
}
public static void remove(Integer toRemove) {
for(Integer integer : integerList) {
if(integer.equals(toRemove)) {
integerList.remove(integer);
}
}
}
public static void main(String... args) {
remove(Integer.valueOf(2));
Integer toRemove = Integer.valueOf(3);
for(Integer integer : integerList) {
if(integer.equals(toRemove)) {
integerList.remove(integer);
}
}
}
}
답변
이유는 다음과 같습니다. Javadoc에서 말하는 것처럼 :
이 클래스의 이터레이터와 listIterator 메소드에 의해 리턴 된 이터레이터는 빠르다 : 이터레이터가 작성된 후 언제라도리스트가 구조적으로 수정되면, 이터레이터 자체의 remove 또는 add 메소드를 제외하고 어떤 식 으로든 이터레이터는 ConcurrentModificationException을 발생시킨다.
이 검사는 next()
스택 트레이스에서 볼 수 있듯이 반복자 의 메소드 에서 수행됩니다 . 그러나 우리는 true로 전달 된 next()
경우에만 메소드에 도달 할 것 hasNext()
입니다. 이는 경계가 충족되는지 확인하기 위해 각각에 의해 호출됩니다. remove 메소드에서 hasNext()
다른 요소를 리턴해야하는지 점검 할 때 두 개의 요소를 리턴했으며 이제 하나의 요소가 제거 된 후 목록에는 두 개의 요소 만 포함됩니다. 그래서 모든 것이 복숭아이며 우리는 반복으로 끝납니다. next()
호출되지 않은 메소드 에서 수행되므로 동시 수정 점검이 수행되지 않습니다 .
다음으로 두 번째 루프로 넘어갑니다. 두 번째 숫자를 제거한 후 hasNext 메소드는 더 많은 값을 반환 할 수 있는지 다시 확인합니다. 이미 두 개의 값을 반환했지만 이제는 목록에 하나만 포함됩니다. 그러나 여기 코드는 다음과 같습니다
public boolean hasNext() {
return cursor != size();
}
1! = 2, 그래서 우리는 next()
방법 을 계속합니다. 이제 누군가 누군가 목록을 엉망으로 만들고 예외를 발생시킵니다.
희망이 당신의 질문을 해결합니다.
요약
List.remove()
ConcurrentModificationException
목록에서 두 번째 마지막 요소를 제거해도 throw되지 않습니다 .
답변
Collection
해당되는 경우 (컬렉션 자체가 아닌) 사본에서 무언가를 제거하기 위해 처리하는 한 가지 방법 . Clone
원본 컬렉션을 통해 Constructor
.
이 예외는 그러한 수정이 허용되지 않을 때 객체의 동시 수정을 감지 한 메소드에 의해 발생할 수 있습니다.
특정 사례의 경우, 먼저 final
선언을지나 목록을 수정하려고 한다고 생각하지 않는 방법 이라고 생각 합니다.
private static final List<Integer> integerList;
또한 원래 목록 대신 사본을 수정하십시오.
List<Integer> copy = new ArrayList<Integer>(integerList);
for(Integer integer : integerList) {
if(integer.equals(remove)) {
copy.remove(integer);
}
}
답변
항목을 제거 할 때 전달 / 반복자 방법이 작동하지 않습니다. 오류없이 요소를 제거 할 수 있지만 제거 된 항목에 액세스하려고하면 런타임 오류가 발생합니다. pushy가 보여 주듯이 ConcurrentModificationException이 발생하므로 반복자를 사용할 수 없으므로 대신 일반 for 루프를 사용하지만 거꾸로 건너 뜁니다.
List<Integer> integerList;
integerList = new ArrayList<Integer>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
int size= integerList.size();
//Item to remove
Integer remove = Integer.valueOf(3);
해결책 :
목록 요소를 제거하려는 경우 배열을 역순으로 순회하십시오. 목록을 거꾸로 이동하면 제거 된 항목을 방문하지 않아도되므로 예외가 제거됩니다.
//To remove items from the list, start from the end and go backwards through the arrayList
//This way if we remove one from the beginning as we go through, then we will avoid getting a runtime error
//for java.lang.IndexOutOfBoundsException or java.util.ConcurrentModificationException as when we used the iterator
for (int i=size-1; i> -1; i--) {
if (integerList.get(i).equals(remove) ) {
integerList.remove(i);
}
}
답변
이 스 니펫은 항상 ConcurrentModificationException을 발생시킵니다.
규칙은 “이터레이터 (for-each 루프를 사용할 때 발생)를 사용하여 반복하는 동안 목록에서 요소를 추가 또는 제거 할 수 없습니다”입니다.
JavaDocs :
이 클래스의 이터레이터와 listIterator 메소드에 의해 리턴 된 이터레이터는 빠르다 : 이터레이터가 작성된 후 언제라도리스트가 구조적으로 수정되면, 이터레이터 자체의 remove 또는 add 메소드를 제외하고 어떤 식 으로든 이터레이터는 ConcurrentModificationException을 발생시킨다.
따라서 목록 (또는 일반적으로 모든 컬렉션)을 수정하려면 수정자를 알고 있으므로 이터레이터를 사용하면 올바르게 처리됩니다.
도움이 되었기를 바랍니다.
답변
나는 같은 문제가 있었지만 반복 된 목록에 en 요소를 추가하는 경우. 내가 이렇게 만들었 어
public static void remove(Integer remove) {
for(int i=0; i<integerList.size(); i++) {
//here is maybe fine to deal with integerList.get(i)==null
if(integerList.get(i).equals(remove)) {
integerList.remove(i);
}
}
}
이제 목록에 반복자를 만들지 않고 “수동으로”반복하므로 모든 것이 잘됩니다. 그리고 i < integerList.size()
목록 감소 / 증가의 목록 크기에서 무언가를 제거 / 추가 할 때 조건 은 결코 당신을 속이지 않을 것입니다.
그것이 도움이되기를 바랍니다.
답변
COW (Copy-On-Write) 컬렉션을 사용하면 작동합니다. 그러나 list.iterator ()를 사용하면 반환 된 Iterator는 다른 스레드가 컬렉션을 수정하더라도 (아래와 같이) list.iterator ()를 호출했을 때와 같이 항상 요소 컬렉션을 참조합니다. copy-on-write-based Iterator 또는 ListIterator (예 : add, set 또는 remove)에서 호출 된 변경 메소드는 UnsupportedOperationException을 발생시킵니다.
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class RemoveListElementDemo {
private static final List<Integer> integerList;
static {
integerList = new CopyOnWriteArrayList<>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
}
public static void remove(Integer remove) {
for(Integer integer : integerList) {
if(integer.equals(remove)) {
integerList.remove(integer);
}
}
}
public static void main(String... args) {
remove(Integer.valueOf(2));
Integer remove = Integer.valueOf(3);
for(Integer integer : integerList) {
if(integer.equals(remove)) {
integerList.remove(integer);
}
}
}
}
답변
이것은 Java 1.6에서 잘 실행됩니다.
~ % javac RemoveListElementDemo.java
~ % java RemoveListElementDemo
~ % 고양이 RemoveListElementDemo.java
import java.util.*;
public class RemoveListElementDemo {
private static final List<Integer> integerList;
static {
integerList = new ArrayList<Integer>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
}
public static void remove(Integer remove) {
for(Integer integer : integerList) {
if(integer.equals(remove)) {
integerList.remove(integer);
}
}
}
public static void main(String... args) {
remove(Integer.valueOf(2));
Integer remove = Integer.valueOf(3);
for(Integer integer : integerList) {
if(integer.equals(remove)) {
integerList.remove(integer);
}
}
}
}
~ %