목록 반복 중에 java.util.List에서 요소를 제거 할 때 ConcurrentModificationException이 발생합니까?
이 질문에 이미 답변이 있습니다.
@Test
public void testListCur(){
List<String> li=new ArrayList<String>();
for(int i=0;i<10;i++){
li.add("str"+i);
}
for(String st:li){
if(st.equalsIgnoreCase("str3"))
li.remove("str3");
}
System.out.println(li);
}
이 코드를 실행하면 ConcurrentModificationException이 발생합니다.
목록에서 지정된 요소를 제거하면 목록의 크기가 변경된 것을 알지 못하는 것처럼 보입니다.
이것이 컬렉션 및 요소 제거와 관련된 일반적인 문제인지 궁금합니다.
이것이 반복하는 동안 컬렉션에서 요소를 제거 할 수 있는 Iterator.remove () 메서드 의 목적이라고 생각합니다 .
예를 들면 :
Iterator<String> iter = li.iterator();
while(iter.hasNext()){
if(iter.next().equalsIgnoreCase("str3"))
iter.remove();
}
반복자없이 목록에서 제거하는 Java 8 방법은 다음과 같습니다.
li.removeIf(<predicate>)
즉
List<String> li = new ArrayList<String>();
// ...
li.removeIf(st -> !st.equalsIgnoreCase("str3"));
이 예외가 항상 다른 스레드에 의해 객체가 동시에 수정되었음을 나타내는 것은 아닙니다. 단일 스레드가 개체의 계약을 위반하는 일련의 메서드 호출을 발행하면 개체가이 예외를 throw 할 수 있습니다. 예를 들어, 스레드가 fail-fast iterator를 사용하여 컬렉션을 반복하는 동안 컬렉션을 직접 수정하는 경우 반복자는이 예외를 처리합니다.
http://download.oracle.com/javase/1.4.2/docs/api/java/util/ConcurrentModificationException.html 에서 가져옴
예, 사람들은 그것에 부딪칩니다. 문제는 목록을 반복하는 동안 목록을 수정할 수 없다는 것입니다. 나는 과거에 두 가지 대안을 사용했습니다.
- 제거 할 항목의 인덱스를 추적 한 다음 반복을 완료 한 후 제거 할 수 있습니다.
- 또는 반복하면서 유지하려는 모든 항목을 새 목록에 복사 한 다음 완료되면 이전 목록을 삭제할 수 있습니다.
이러한 옵션은 제거 할 요소를 찾기 위해 목록을 반복해야한다고 가정합니다. 목록 요소가 테스트 할 수있는 속성이있는 복잡한 개체 인 경우 유용합니다.
특별한 경우에는 removeAll을 사용할 수 있으므로 반복 할 필요조차 없습니다. 여기 에서 API를 보십시오 . 인수에 포함되지 않은 모든 것을 버리는 retainAll과 같은 멋진 메소드도 있습니다. 목록의 객체가 같고 해시 코드를 올바르게 구현할 때마다 제거 / 유지 유사 메서드를 사용할 수 있습니다. 앱의 인스턴스 간 동등성을 식별하기 위해 equals / hashcode에 의존 할 수없는 경우 직접 제거해야합니다 ....
Java 8 버전을 언급 할 가치가 있다고 생각합니다.
@Test
public void testListCur() {
List<String> li = new ArrayList<String>();
for (int i = 0; i < 10; i++) {
li.add("str" + i);
}
li = li.stream().filter(st -> !st.equalsIgnoreCase("str3")).collect(Collectors.toList());
System.out.println(li);
}
for-each 루프에서 직접 요소를 제거하려는 목록의 복사본을 만들 수 있습니다. 저에게는 이것이 가장 간단한 방법입니다. 이 같은:
for (String stringIter : new ArrayList<String>(myList)) {
myList.remove(itemToRemove);
}
도움이 되길 바랍니다 ..
이것을 시도하십시오 (Java 8) :
list.removeIf(condition);
나는이 문제가 있었고 더 쉬운 방법은 hvgotcodes가 준 두 번째 방법과 동일하다고 생각합니다.
또는 반복하면서 유지하려는 모든 항목을 새 목록에 복사 한 다음 완료되면 이전 목록을 삭제할 수 있습니다.
@Test
public void testListCur(){
List<String> li=new ArrayList<String>();
for(int i=0;i<10;i++){
li.add("str"+i);
}
List<String> finalLi = new ArrayList<String>();
for(String st:li){
if(st.equalsIgnoreCase("str3")){
// Do nothing
} else {
finalLi.add(st);
}
}
System.out.println(finalLi);
}
ArrayList에 필드가 있음 modCount
-컬렉션 수정 횟수
메소드를 호출 iterator()
하면 새 객체가 생성 Itr
됩니다. 필드가 있습니다 expectedModCount
. expectedModCount
필드는 modCount
값으로 초기화됩니다 . 호출 할 때
li.remove("str3");
modCount
증분. 언제 li
반복자 를 통해 액세스를 시도합니까?expectedModCount == modCount
그리고 그것이 거짓 던지면 ConcurrentModificationException
Hence if you get iterator and after collection modified - iterator is considered not valid and you cannot use it.
I looped a different way...
public void testListCur(){
List<String> li=new ArrayList<String>();
for(int i=0;i<10;i++){
li.add("str"+i);
}
for(int i=0; i<li.size(); i++)
if(li.get(i).equalsIgnoreCase("str3"))
li.remove(i--);
System.out.println(li);
}
I think that best answer is from bigdev.de, but i would like to add something to it(like if the item is removed from a list, maybe you would like to log that somewhere or something):
List<String> list = new ArrayList<>();
list.removeIf(a -> {
boolean condition = a.equalsIgnoreCase("some condition");
if(condition)
logger.info("Item removed from the list: " + a);
return condition;
});
'Program Tip' 카테고리의 다른 글
여러 선택적 매개 변수를 C # 함수에 전달 (0) | 2020.12.03 |
---|---|
WebView의 HTTP 요청 가로 채기 및 재정의 (0) | 2020.12.03 |
알 수없는 유형 이름 'uint8_t', MinGW (0) | 2020.12.03 |
주어진 텍스트 파일에서 모든 공백을 제거하는 방법 (0) | 2020.12.03 |
JavaScript에서 객체 배열을 인쇄하는 방법은 무엇입니까? (0) | 2020.12.03 |