반복문에서 List 순환 중에 아이템을 안전하게 삭제하는 방법들을 소개합니다.
For Loop를 이용하여 List 순회(Iterating) 중에, 어떤 아이템을 삭제하면 Exception이 발생하거나 어떤 아이템을 탐색하지 못하는 문제가 발생할 수 있습니다.
문제점들을 먼저 알아보고, 해결 방법을 소개합니다.
- 문제 1: ConcurrentModificationException 발생 가능성
- 문제 2: 반복문에서 순회 중, 일부 요소가 탐색에서 누락될 수 있는 가능성
- 해결 방법 1: List의 높은 Index에서 낮은 Index 방향으로 순회
- 해결 방법 2: 탐색 후, 나중에 삭제
- 해결 방법 3: Collection.removeIf()
- 해결 방법 4: Iterator
문제 1: ConcurrentModificationException 발생 가능성
다음과 같이 for loop에서 ArrayList의 특정 아이템을 삭제하게 되면 ConcurrentModificationException가 발생할 수 있습니다. 순회 중에 리스트의 아이템을 삭제했을 때, 다음에 참조하는 아이템의 Index가 List의 범위를 벗어 나게 될 수 있는데, 이 때 Exception이 발생합니다.
다음 코드는 순회 중에 Exception이 발생합니다. 이런 코드는 잠재적인 문제가 있습니다.
import java.util.ArrayList;
import java.util.List;
public class RemoveFromListIterating1 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("apple");
list.add("kiwi");
list.add("melon");
list.add("banana");
for (String item : list) {
if (item.equals("kiwi")) {
list.remove(item);
}
}
}
}
Output:
Exception in thread "main" java.util.ConcurrentModificationException
at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1013)
at java.base/java.util.ArrayList$Itr.next(ArrayList.java:967)
at RemoveFromListIterating1.main(RemoveFromListIterating1.java:13)
문제 2: 반복문에서 순회 중, 일부 요소가 탐색에서 누락될 수 있는 가능성
ConcurrentModificationException가 발생하지 않아도, 낮은 Index에서 높은 Index로 탐색하면서 아이템을 삭제하게 되면, 탐색에서 제외되는 아이템이 있을 수 있습니다.
아래 코드를 실행해 보면 리스트 순회 중, kiwi
는 탐색되지 못하였습니다. 따라서, 이런 코드도 잠재적인 문제가 있습니다.
List<String> list = new ArrayList<>();
list.add("apple");
list.add("kiwi");
list.add("melon");
list.add("banana");
for (int i = 0; i < list.size(); i++) {
String item = list.get(i);
System.out.println("Iterating: " + item);
if (item.equals("apple") || item.equals("kiwi")) {
list.remove(item);
}
}
System.out.println(list);
Output:
Iterating: apple
Iterating: melon
Iterating: banana
[kiwi, melon, banana]
해결 방법 1: List의 높은 Index에서 낮은 Index 방향으로 순회
List의 높은 Index에서 낮은 Index 방향으로 순회하면, for loop에서 아이템을 안전하게 삭제할 수 있습니다. 아이템 삭제가 다음에 탐색할 아이템의 Index에 영향을 주지 않기 때문입니다.
import java.util.ArrayList;
import java.util.List;
public class RemoveFromListIterating2 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("apple");
list.add("kiwi");
list.add("melon");
list.add("banana");
for (int i = (list.size() - 1); i > -1; i--) {
String item = list.get(i);
System.out.println("Iterating: " + item);
if (item.equals("kiwi")) {
list.remove(item);
}
}
System.out.println("Result: " + list);
}
}
Output:
Iterating: banana
Iterating: melon
Iterating: kiwi
Iterating: apple
Result: [apple, melon, banana]
해결 방법 2: 탐색 후, 나중에 삭제
두개의 for loop를 사용하여 아이템을 삭제하는 방법입니다.
첫번째 Loop에서 삭제할 아이템을 다른 리스트에 저장하고, 두번째 Loop에서 아이템을 안전하게 삭제할 수 있습니다.
import java.util.ArrayList;
import java.util.List;
public class RemoveFromListIterating2_1 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("apple");
list.add("kiwi");
list.add("melon");
list.add("banana");
List<String> removed = new ArrayList<>();
for (String item : list) {
System.out.println("Iterating: " + item);
if (item.equals("kiwi")) {
removed.add(item);
}
}
for (String item : removed) {
list.remove(item);
}
System.out.println("Result: " + list);
}
}
Output:
Iterating: apple
Iterating: kiwi
Iterating: melon
Iterating: banana
Result: [apple, melon, banana]
해결 방법 3: Collection.removeIf()
Collection.removeIf()
는 인자로 함수형 인터페이스 Predicate를 전달하며, 조건에 맞는 아이템을 안전하게 삭제합니다.
import java.util.ArrayList;
import java.util.List;
public class RemoveFromListIterating3 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("apple");
list.add("kiwi");
list.add("melon");
list.add("banana");
list.removeIf(item -> item.equals("kiwi"));
System.out.println("Result: " + list);
}
}
Output:
Result: [apple, melon, banana]
해결 방법 4: Iterator
Iterator를 이용하여 리스트를 순회하고, 특정 아이템을 안전하게 삭제할 수 있습니다.
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class RemoveFromListIterating4 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("apple");
list.add("kiwi");
list.add("melon");
list.add("banana");
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String item = it.next();
System.out.println("Iterating: " + item);
if (item.equals("kiwi")) {
it.remove();
}
}
System.out.println("Result: " + list);
}
}
Output:
Iterating: apple
Iterating: kiwi
Iterating: melon
Iterating: banana
Result: [apple, melon, banana]
Related Posts
- Java - Unsupported class file major version 61 에러
- Java - String.matches()로 문자열 패턴 확인 및 다양한 예제 소개
- Java - 문자열 공백제거 (trim, replace)
- Java - replace()와 replaceAll()의 차이점
- Java - ArrayList 초기화, 4가지 방법
- Java - 배열 정렬(Sorting) (오름차순, 내림차순)
- Java - 문자열(String)을 비교하는 방법 (==, equals, compare)
- Java - StringBuilder 사용 방법, 예제
- Java - 로그 출력, 파일 저장 방법 (Logger 라이브러리)
- Java IllegalArgumentException 의미, 발생 이유
- Java - NullPointerException 원인, 해결 방법
- Seleninum의 ConnectionFailedException: Unable to establish websocket connection 해결
- Java - compareTo(), 객체 크기 비교
- Java - BufferedWriter로 파일 쓰기
- Java - BufferedReader로 파일 읽기
- Java charAt() 함수 알아보기
- Java - BigInteger 범위, 비교, 연산, 형변환
- Java contains()로 문자(대소문자 X) 포함 확인
- Java - Set(HashSet)를 배열로 변환
- Java - 문자열 첫번째 문자, 마지막 문자 확인
- Java - 문자열 한글자씩 자르기
- Java - 문자열 단어 개수 가져오기
- Java - 1초마다 반복 실행
- Java - 배열을 Set(HashSet)로 변환
- Java - 여러 Set(HashSet) 합치기
- Java - 명령행 인자 입력 받기
- Java - 리스트 역순으로 순회, 3가지 방법
- Java - 특정 조건으로 리스트 필터링, 3가지 방법
- Java - HashMap 모든 요소들의 합계, 평균 계산
- Java - 특정 조건으로 HashMap 필터링
- Java - 싱글톤(Singleton) 패턴 구현
- Java - 숫자 왼쪽에 0으로 채우기
- Java - String 배열 초기화 방법
- Java - 정렬된 순서로 Map(HashMap) 순회
- Java - HashMap에서 key, value 가져오기