본문 바로가기

Java

[JAVA] 반복문(for문)안에서 삭제 시 생기는 에러(ConcurrentModificationException )

반복문을 돌리면서 특정 원소를 삭제하던 중 제거되어야 하는 리스트가 제거되지 않는다는 걸 깨달았다.

 

처음 오류가 난 코드를 공유한다.

List<example> exampleList = exampleService.selectExampleList();

exampleList.forEach(item -> {
	
    if("삭제".equals(item)){
    	exampleList.remove(item);
    }
    
});

 

무엇이 문제인지 처음엔 몰랐다.

마찬가지로 아래의 코드에서도 동일한 오류가 발생했다.

List<example> exampleList = exampleService.selectExampleList();

for (example exampleList : item) {
  if ("삭제".equals(item)) {
    exampleList.remove(item);
  }
}
List<example> exampleList = exampleService.selectExampleList();

for (int i = 0; i < exampleList.size(); i++) {
	example item = exampleList.get(i);
    if ("삭제".equals(item)) {
    	exampleList.remove(item);
    }
}

왜?

원인은 반복문이 순회하는 동안 Collection(exampleList)가 변경되면  ConcurrentModificationException을 발생시키기 때문이다. 구조적  변경(List의 사이즈 변경)은 진행중인 반복에 잘못된 결과를 유발할 수 있다는게 원인이였다. remove와 마찬가지로 next, set, add 등도 ConcurrentModificationException을 발생시킬 수 있다.

 

자세히 들어가면?

public boolean remove(Object o)
Removes the first occurrence of the specified element from this list, if it is present. If the list does not contain the element, it is unchanged. More formally, removes the element with the lowest index i such that (o==null ? get(i)==null : o.equals(get(i))) (if such an element exists). Returns true if this list contained the specified element (or equivalently, if this list changed as a result of the call).
Specified by:
remove in interface Collection<E>
Specified by:
remove in interface List<E>
Overrides:
remove in class AbstractCollection<E>
Parameters:
o - element to be removed from this list, if present
Returns:
true if this list contained the specified element

https://docs.oracle.com/javase/8/docs/api/

 

Java Platform SE 8

 

docs.oracle.com


방안1

List<example> exampleList = exampleService.selectExampleList();
//반복문을 처리후나 반복문을 생략하고 removeIf 활용
exampleList.removeIf(item -> "삭제".equals(item));

방안2

List<example> exampleList = exampleService.selectExampleList();

Iterator iter = exampleList.iterator();

while(iter.hasNext()) {

    if ("삭제".equals(item)) {
    	iter.remove();
    }
    
}

방안3

List<example> exampleList = exampleService.selectExampleList();

exampleList.stream().filter(item -> item.getName().equals("삭제")).collect(Collectors.toList());

방안4

 

List<example> exampleList = exampleService.selectExampleList();

exampleList.stream().filter(item -> {
	
    boolean result=false;
    
    for (example x:item.getExampleList()) {
        if(x.getName().equals("삭제")){
            result= true;
            break;
        }
    }
    return result;
}).collect(Collectors.toList());

* 나는 조건을 많이 거는 코드라 2번 방안으로 해결하였다.