Java - 반복문 안에서 List의 요소 삭제 방법

반복문에서 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]
Loading script...

Related Posts

codechachaCopyright ©2019 codechacha