본문 바로가기
Java/Java이론

List 자주 발생하는 리스트 관련 예외 및 해결 방법

by P_eli 2024. 11. 8.
728x90
반응형

리스트를 다루다 보면 다양한 예외가 발생할 수 있습니다. 특히, IndexOutOfBoundsException, ConcurrentModificationException 등의 예외는 자주 발생하며, 코드의 안정성을 떨어뜨릴 수 있습니다. 이번 글에서는 이런 예외가 발생하는 원인과 방지 방법에 대해 알아보고, 실제 예외 상황을 재현하며 해결책을 제시해 보겠습니다.

 

1. IndexOutOfBoundsException

예외 발생 원인

IndexOutOfBoundsException는 리스트의 유효한 범위를 벗어난 인덱스에 접근하려고 할 때 발생합니다. 예를 들어, 리스트의 크기가 10인데 인덱스 10 이상의 위치에 접근하려고 하면 이 예외가 발생합니다. 리스트의 인덱스는 0부터 시작하기 때문에, 유효한 인덱스 범위는 [0, list.size() - 1]가 됩니다.

예시 코드

List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");

// 예외 발생 코드
System.out.println(list.get(2)); // IndexOutOfBoundsException

 

위 코드에서 list.get(2)는 리스트에 없는 인덱스 2에 접근하려고 하므로 IndexOutOfBoundsException이 발생합니다.

해결 방법

  1. 인덱스 범위 확인: 인덱스를 사용할 때 항상 리스트의 크기를 확인합니다.
  2. 범위 내 반복문 사용: 반복문에서 리스트의 길이를 넘지 않도록 주의합니다.

해결 코드

List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");

int index = 2;
if (index < list.size()) {
    System.out.println(list.get(index));
} else {
    System.out.println("Invalid index: " + index);
}

또는 반복문을 사용할 때 for-each 구문을 사용하여 안전하게 리스트를 순회할 수 있습니다.

 

2. ConcurrentModificationException

예외 발생 원인

ConcurrentModificationException는 리스트를 반복하면서 동시에 리스트를 수정하려고 할 때 발생합니다. 예를 들어, for-each 문이나 iterator를 사용하여 리스트를 순회하는 도중에 리스트의 요소를 추가 또는 제거하려고 하면 이 예외가 발생합니다.

예시 코드

List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");

for (String fruit : list) {
    if (fruit.equals("Banana")) {
        list.remove(fruit); // ConcurrentModificationException
    }
}

위 코드에서는 for-each 문을 통해 리스트를 순회하면서 요소를 삭제하려고 해서 ConcurrentModificationException이 발생합니다.

해결 방법

  1. Iterator 사용: Iterator의 remove 메서드를 사용하여 안전하게 요소를 삭제할 수 있습니다.
  2. 반복문 사용: 리스트의 크기가 변경될 때 for문을 사용해 인덱스 기반으로 요소를 삭제하거나 수정합니다.

해결 코드 (Iterator 사용)

List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");

Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String fruit = iterator.next();
    if (fruit.equals("Banana")) {
        iterator.remove(); // 안전하게 요소 삭제
    }
}

 

해결 코드 (인덱스 기반 반복문 사용)

List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");

for (int i = 0; i < list.size(); i++) {
    if (list.get(i).equals("Banana")) {
        list.remove(i);
        i--; // 인덱스를 조정하여 예외 방지
    }
}

 

심화 개념: 예외 발생 원인 분석 및 방지 패턴

1. IndexOutOfBoundsException 원인 분석 및 방지 패턴

리스트의 인덱스를 직접 지정할 때, 유효한 범위 내에 있는지 항상 확인해야 합니다. 또한, 리스트에 add나 remove 작업을 빈번히 수행할 경우, 크기 변화를 추적해야 예외를 방지할 수 있습니다.

방지 패턴

  • 안전한 접근: 리스트의 크기를 조건으로 설정하여, 범위를 벗어나지 않도록 조건을 강화합니다.
  • 검증 로직 추가: 인덱스 접근 전, 크기 검증 로직을 사용하여 예외를 방지합니다.

2. ConcurrentModificationException 원인 분석 및 방지 패턴

ConcurrentModificationException은 리스트 순회 도중 수정 작업을 금지하는 내부 구조 때문입니다. 이 예외는 Java의 fail-fast 메커니즘에 따라 리스트가 예상치 않게 수정될 경우 발생합니다.

방지 패턴

  • Iterator 사용: Iterator를 통해 요소를 삭제하면 안전하게 수정 작업을 수행할 수 있습니다.
  • 컬렉션 복사: 컬렉션을 복사한 후 복사된 컬렉션을 순회하면서 원본 리스트를 수정하는 방법도 있습니다. 이 방식은 성능에는 불리하지만, 데이터 일관성 측면에서 유리합니다.

 

정리

리스트를 다룰 때는 다양한 예외가 발생할 수 있으며, 특히 IndexOutOfBoundsExceptionConcurrentModificationException는 주의해서 다루어야 합니다. 인덱스 범위를 확인하고, Iterator를 사용하는 등 예외 발생을 예방하는 패턴을 잘 익혀둔다면 코드의 안정성과 가독성을 높일 수 있습니다.

728x90
반응형