리스트를 다루다 보면 다양한 예외가 발생할 수 있습니다. 특히, 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이 발생합니다.
해결 방법
- 인덱스 범위 확인: 인덱스를 사용할 때 항상 리스트의 크기를 확인합니다.
- 범위 내 반복문 사용: 반복문에서 리스트의 길이를 넘지 않도록 주의합니다.
해결 코드
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이 발생합니다.
해결 방법
- Iterator 사용: Iterator의 remove 메서드를 사용하여 안전하게 요소를 삭제할 수 있습니다.
- 반복문 사용: 리스트의 크기가 변경될 때 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를 통해 요소를 삭제하면 안전하게 수정 작업을 수행할 수 있습니다.
- 컬렉션 복사: 컬렉션을 복사한 후 복사된 컬렉션을 순회하면서 원본 리스트를 수정하는 방법도 있습니다. 이 방식은 성능에는 불리하지만, 데이터 일관성 측면에서 유리합니다.
정리
리스트를 다룰 때는 다양한 예외가 발생할 수 있으며, 특히 IndexOutOfBoundsException과 ConcurrentModificationException는 주의해서 다루어야 합니다. 인덱스 범위를 확인하고, Iterator를 사용하는 등 예외 발생을 예방하는 패턴을 잘 익혀둔다면 코드의 안정성과 가독성을 높일 수 있습니다.
'Java > Java이론' 카테고리의 다른 글
CopyOnWriteArrayList란 무엇인가? (0) | 2024.11.14 |
---|---|
ConcurrentHashMap: 멀티스레드 환경을 위한 고성능 해시 맵 (1) | 2024.11.13 |
List 정렬과 Comparator/Comparable 인터페이스 활용 (0) | 2024.11.06 |
List와 배열 간의 상호 변환 (0) | 2024.11.04 |
List의 효율적인 탐색 및 수정 방법 (0) | 2024.11.01 |