DEV/Java

[java 기초] Iterator 활용 ConcurrentModificationException 예외 해결

Bi3a 2023. 9. 1. 01:30

반응형

Iterator 활용 ConcurrentModification Exceptio 예외 처리
java 깨부시기

 

 

    ConcurrentModificationException이란?

     

     

    Iterable의 하위 자료구조들
    Iterable -> Collection -> 하위 자료구조들

     

    ConcurrentModificationException은 Iterable 한(반복가능한) Collection 프레임워크 내 자료구조에서 일어납니다.
    정의하자면 'Iteration(반복)이 진행되는 동안 해당 반복을 진행하는 요소가 변경되는 경우' 발생하는 예외입니다.

    상기 예외는 데이터 동기화를 지원하지 않는 Collection에서 요소 내 순회와 탐색 등이 동시에 일어나지 않게끔
    동시성을 제어하며 데이터의 무결성을 보장합니다.

    일반적으로 Collection 인터페이스를 상속받는 자료구조의 객체를 반복문을 통해 요소 탐색을 하던 과정에서
    객체 내부 요소에 삭제, 수정 행위가 일어나는 경우 흔히 발생합니다.

     

    ConcurrentModificationException 예외가 발생하는 경우(코드 예제)

     

    import java.util.*;
    public class Test {
        public static void main(String[] args) {
            List<Integer> al = new ArrayList<>(){
                {
                    for(int i = 1; i <= 10; i++){
                        add(i);
                    }
                }
            };
            // al 내 요소가 짝수 일 시 al에서 remove
            for (int target : al) {
                if (target % 2 == 0) {
                    al.remove(target);
                }
            }
            System.out.println(al);
            // out : "ConcurrentModificationException 발생
        }
    }
    예제에서도 ArrayList 객체를 for each를 통해 객체 내부 요소에 대해 순회하며 특정 값에 도달 시 객체 내부의 요소를 제거하는 처리를 수행하고 있습니다.

    위와 같은 코드는 Iterator에 의한 순회가 종료되지 않았음에도 내부 요소를 변경함에 따라 ConcurrentModificationException 예외를 발생시킵니다.

    객체의 index 접근을 통한 for loop 순회도 indexOutOfBoundsException 예외를 발생시킬 가능성이 높음에 따라
    두 가지 접근 방법 모두 좋은 방식의 코드 작성 방법은 아닌 것 같습니다.

     

    그렇다면 순회를 진행하며 객체 요소를 수정하는 방법은 무엇이 있을까요?

    바로 Iterator를 활용하는 것입니다.

     

    Iterator(반복자)

     

    Iterator는 Collection 프레임워크 자료구조 객체 내부의 요소를 순회하는 데 특화되어 있는 인터페이스입니다.
    Iterator가 가지고 있는 메서드는 총 4개입니다.
    • public boolean hasNext() : 객체 내 읽어올 다음 요소가 있는 지를 반환합니다. (있으면 true, 없으면 false)
    • public Object next() : 객체 내 다음 요소를 반환합니다.
    • public remove() : next() 로 읽어온 요소를 삭제합니다. 
    • Default void foeEachRemaining(Consumer <? super E> action) : 모든 요소가 처리되거나 작업에서 예외가 발생할 때 까지 나머지 요소들에 대해 지정된 작업을 수행합니다.

     

    Iterator는 ConcurrentModificationException이 일어나는 지를 확인하면서 순회하기 때문에
    순회 중간에 Collection의 요소가 변경되더라도 예외를 발생시키지 않습니다.

     

    Iterator 활용한 요소 삭제(코드 예제)

    import java.util.*;
    public class Test {
        public static void main(String[] args) {
            List<Integer> al = new ArrayList<>() {
                {
                    for (int i = 1; i <= 10; i++) {
                        add(i);
                    }
                }
            };
    
            Iterator<Integer> iter = al.iterator();
            // al 내 요소가 짝수 일 시 al에서 remove
            int target;
            while (iter.hasNext()) {
                target = iter.next();
                if (target % 2 == 0) {
                    iter.remove();
                }
            }
            System.out.println(al);
            // out : "[1, 3, 5, 7, 9]"
        }
    }

     

    의도했던 대로 객체 내 짝수 요소가 다 제거된 것을 확인할 수 있습니다.

     

     

    Iterator 단점

    • 대용량의 데이터 처리에서 for loop보다 시간복잡도가 증가, 처리능력이 떨어집니다. (처리 간 객체를 생성하기 때문)
    • 일반적으로 순차 접근만 허용하며, index에 따른 접근은 허용하지 않습니다.

     

     

     

     

     

     

     

     

    Reference

     

    Java - ConcurrentModificationException 원인 및 해결 방법

    ConcurrentModificationException는 보통 리스트나 Map 등, Iterable 객체를 순회하면서 요소를 삭제하거나 변경을 할 때 발생합니다. removeIf, removeAll, Iterable 등의 메소드를 이용하여 리스트 순회 중 요소를

    codechacha.com

     

    [Java] ConcurrentModificationException 원인과 해결방법

    자바 언어로 프로그래밍을 하다보면 가끔씩 ConcurrentModificationException을 만나게 된다. ConcurrentModificationException의 발생 원인과 해결방법에 대해서 간단하게 소개하겠다. ConcurrentModificationException Conc

    hbase.tistory.com

     

    [JAVA] java 개발자라면 한번 쯤은 겪을 ConcurrentModificationException

    지난 포스트에서는 일반 for문과 for-each 문과 Iterator에 대하여 포스팅했었습니다. 이번 포스팅은 for-each문에서 발생하는 ConcurrentModificationException에 대해서 포스팅하겠습니다. ConcurrentModificationExcep

    jyyoun1022.tistory.com

     

    반응형