Java - List 순회 중, 아이템 삭제

By JS | Last updated: June 05, 2021

이 글에서는 List 순환 중에 아이템을 안전하게 삭제하는 방법들을 소개합니다.

For Loop를 이용하여 List 순회(Iterating) 중에, 어떤 아이템을 삭제하면 Exception이 발생하거나 어떤 아이템을 탐색하지 못하는 문제가 발생할 수 있습니다.

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)

순회 중 누락되는 아이템

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

댓글을 보거나 쓰려면 이 버튼을 눌러주세요.
codechachaCopyright ©2019 codechacha