본문 바로가기
Android/Exceptions

Iterator ::: java.util.ConcurrentModificationException

by featherwing 2020. 6. 28.
반응형

 

1.  List에서 특정 조건을 가진항목을 삭제하던 중 발생하였습니다

   List<DTOsomething> mList = new ArrayList<>();
   
   public void deleteItem(String Title) {
        	for(int i=0; i<mList.size(); i++) {
            	DTOsomething mDTO = mList.get(i);
            	String title_inList = mDTO.getName();
            	if(title_inList.equals(Title)) {
                	mList.remove(mDTO);
            	}
                    refreshList();
        }

DTO를 가진 List에서 for 구문을 이용해서, DTO의 name과 Title 을 비교한 뒤, 같다면 삭제해주는 내용입니다.

 

해당 Exception이 항상 발생하지는 않는데, exception이 발생하지 않더라도, 리스트가 완벽하게 필터링 되지 않습니다.

 

name과 Title이 같은 리스트 아이템이라도 삭제되지 않고 남아 있는 경우가 있습니다.

 

 

List의 직접적인 편집을 하는 경우는 잘 없었는데요, 보통은 SQLite에서 cursor를 이용해서 필요한 리스트아이템들만 가져오는 경우가 많아 직접적인 편집을 할 필요가 없었기 때문에 볼 수 없었습니다.

 

 

 

2. 발생원인은 for 루프 내부에서 List의 크기와 인덱스가 불일치 하기 때문에, ConcurrentModificationException이 발생하거나 논리오류로 항목이 삭제되지 않고 남는 경우가 발생한다고 합니다.

 

특정 List를 직접적으로 편집하는 remove에서만 발생하는것을 확인했고, List A에서 조건이 일치하는 항목을 List B에 add 하는 경우에는 for문을 쓰더라도 발생하지 않는것을 확인했습니다. 아마도, 삭제시에만 인덱스 불일치가 발생하기 때문에 일어나는 상황으로 생각됩니다.

 

 

3. 이 오류를 해결하기 위해서 이미 Iterator라는 Framework가 존재합니다.  위의 코드는 Iterator를 사용하여 아래와 같이 구현 할 수 있습니다.

   List<DTOsomething> mList = new ArrayList<>();
   
public void deleteItem(String Title) {

        Iterator<DTOsomething> iter = mList.iterator();
        while(iter.hasNext()) {
            if(tTitle.equals(iter.next().getName())) {
                iter.remove();
            }
        }
 refreshList();
    }

 

DTO가 아닌 일반적인 사용은 아래와 같이 사용합니다.

   List<String> mList = new ArrayList<>();

public void removeItem(String Title) {

        Iterator iter = list.iterator();
        while(iter.hasNext()) {
            if(Title.equals(iter.next())) {
                iter.remove();
            }
        }
        refreshList();
    }

 

Iterator에 대한 자세한 내용은 안드로이드 개발자 문서를 참고 해 주세요.

반응형

댓글