Dandy Now!
  • [Java] 자바에서 Iterator를 사용하는 이유
    2025년 03월 01일 21시 40분 00초에 업로드 된 글입니다.
    작성자: DandyNow
    728x90
    반응형

    1. 자바에서 Iterator를 사용하는 이유

    1. 컬렉션 순회 표준화

    • 자바의 다양한 컬렉션(List, Set, Map 등)은 내부 구조가 다르기 때문에, 각 컬렉션에 맞는 순회 방식이 필요하다.
    • Iterator는 이러한 다양한 컬렉션을 일관된 방식으로 순회할 수 있도록 표준화된 인터페이스를 제공한다.
    • 즉, 컬렉션의 종류에 상관없이 hasNext()next() 메서드를 사용하여 요소에 접근할 수 있다.

    ✅ 예제 코드

    Iterator를 사용하면 List, Set 등 다양한 컬렉션을 일관된 방식으로 순회할 수 있다.

    import java.util.*;
    
    public class IteratorExample1 {
        public static void main(String[] args) {
            List<String> list = Arrays.asList("Apple", "Banana", "Cherry");
            Set<String> set = new HashSet<>(list);
    
            // List 순회
            Iterator<String> listIterator = list.iterator();
            while (listIterator.hasNext()) {
                System.out.println("List item: " + listIterator.next());
            }
    
            // Set 순회
            Iterator<String> setIterator = set.iterator();
            while (setIterator.hasNext()) {
                System.out.println("Set item: " + setIterator.next());
            }
        }
    }

    💡 ListSet의 내부 구조는 다르지만, Iterator를 사용하여 동일한 방식으로 요소를 순회할 수 있다.


    2. 요소의 안전한 제거

    • 일반적인 for 루프나 향상된 for-each 루프를 사용하여 컬렉션을 순회하면서 요소를 제거하면 ConcurrentModificationException이 발생할 수 있다.
    • Iteratorremove() 메서드를 사용하면 순회 중에도 안전하게 요소를 제거할 수 있다.

    ✅ 예제 코드

    Iteratorremove() 메서드를 사용하면 ConcurrentModificationException 없이 요소를 안전하게 제거할 수 있다.

    import java.util.*;
    
    public class IteratorExample2 {
        public static void main(String[] args) {
            List<String> list = new ArrayList<>(Arrays.asList("Apple", "Banana", "Cherry"));
    
            Iterator<String> iterator = list.iterator();
            while (iterator.hasNext()) {
                String fruit = iterator.next();
                if ("Banana".equals(fruit)) {
                    iterator.remove();  // 안전하게 요소 제거
                }
            }
    
            System.out.println("Updated list: " + list); // [Apple, Cherry]
        }
    }

    💡 for-each 루프에서 list.remove()를 직접 호출하면 ConcurrentModificationException이 발생할 수 있지만, Iteratorremove()를 사용하면 안전하게 삭제할 수 있다.


    3. 다양한 순회 방식 지원

    • Iterator는 기본적으로 단방향 순회만 지원한다.
    • ListIterator를 사용하면 previous() 메서드를 이용하여 양방향 순회가 가능하다.
    • 예를 들어, ArrayList에서 ListIterator를 사용하면 앞뒤로 이동하며 요소를 탐색할 수 있다.

    ✅ 예제 코드

    ListIterator를 사용하면 양방향 순회가 가능하다.

    import java.util.*;
    
    public class IteratorExample3 {
        public static void main(String[] args) {
            List<String> list = new ArrayList<>(Arrays.asList("Apple", "Banana", "Cherry"));
    
            ListIterator<String> listIterator = list.listIterator();
    
            // 정방향 순회
            while (listIterator.hasNext()) {
                System.out.println("Forward: " + listIterator.next());
            }
    
            // 역방향 순회
            while (listIterator.hasPrevious()) {
                System.out.println("Backward: " + listIterator.previous());
            }
        }
    }

    💡 ListIteratorprevious()를 지원하여 앞뒤로 이동이 가능하며, Iterator보다 더 다양한 기능을 제공한다.


    4. 컬렉션의 내부 구조 은닉

    • Iterator를 사용하면 컬렉션의 내부 구현을 알 필요 없이 요소를 순회할 수 있다.
    • 이를 통해 컬렉션의 종류가 변경되더라도 Iterator를 사용하는 코드의 변경을 최소화할 수 있다.
    • 다만, 컬렉션의 종류에 따라 성능이나 지원하는 기능이 달라질 수 있으므로, 적절한 컬렉션을 선택하는 것이 중요하다.

    ✅ 예제 코드

    Iterator를 사용하면 컬렉션의 구현 방식을 몰라도 동일한 방식으로 요소를 가져올 수 있다.

    import java.util.*;
    
    public class IteratorExample4 {
        public static void main(String[] args) {
            Collection<String> collection;
    
            if (new Random().nextBoolean()) {
                collection = new ArrayList<>(Arrays.asList("Apple", "Banana", "Cherry"));  // List 사용
            } else {
                collection = new HashSet<>(Arrays.asList("Apple", "Banana", "Cherry"));  // Set 사용
            }
    
            // 컬렉션 타입이 List인지 Set인지 몰라도 동일한 방식으로 순회 가능
            Iterator<String> iterator = collection.iterator();
            while (iterator.hasNext()) {
                System.out.println("Item: " + iterator.next());
            }
        }
    }

    💡 collectionArrayList일 수도 있고, HashSet일 수도 있지만, Iterator를 사용하면 이를 신경 쓸 필요 없이 동일한 방식으로 요소를 가져올 수 있다.


    📌 정리

    이유 주요 기능 코드 예제
    1. 컬렉션 순회 표준화 ListSet을 동일한 방식으로 순회 ListSet을 같은 Iterator 방식으로 순회
    2. 요소의 안전한 제거 remove()를 사용해 ConcurrentModificationException 방지 Iterator.remove()를 사용하여 안전하게 요소 삭제
    3. 다양한 순회 방식 지원 ListIterator로 양방향 순회 가능 next()previous()를 사용한 순회
    4. 컬렉션의 내부 구조 은닉 컬렉션이 List인지 Set인지 몰라도 순회 가능 Collection을 다형성을 이용해 Iterator로 순회

    2. Iterator를 적극적으로 사용하는 대표적인 라이브러리

    1. Java Collections Framework (JCF)

    1️⃣ 대표적인 예: ArrayList, HashSet, TreeMap

    자바의 기본 컬렉션 프레임워크(java.util 패키지)는 대부분 Iterator를 지원하며, iterator() 메서드를 통해 요소를 순회할 수 있다.

    2️⃣ 활용 이유: 컬렉션 내부 구조를 몰라도 일관된 방식으로 순회 가능

    3️⃣ 사용 예 (Iterator를 이용한 컬렉션 순회)

    List<String> list = new ArrayList<>(Arrays.asList("Apple", "Banana", "Cherry"));
    Iterator<String> iterator = list.iterator();
    
    while (iterator.hasNext()) {
        System.out.println(iterator.next());
    }

    ✅ 현재 권장되는 방식 (forEach 사용)

    list.forEach(System.out::println);

    📌 하지만, Iterator.remove()를 사용해야 하는 경우에는 여전히 Iterator를 활용하는 것이 필요하다.


    2. Apache Commons Collections

    1️⃣ 대표적인 예: org.apache.commons.collections4.IteratorUtils

    Apache Commons Collections는 컬렉션을 다룰 때 유용한 기능을 제공하는 라이브러리이다.
    이 라이브러리의 IteratorUtils 클래스는 Iterator 변환, 필터링, 체이닝 등 다양한 기능을 제공한다.

    2️⃣ 활용 이유: Iterator를 불변(immutable)으로 만들거나, 필터링된 Iterator 생성 가능

    3️⃣ 사용 예 (불변 Iterator 생성)

    import org.apache.commons.collections4.IteratorUtils;
    import java.util.*;
    
    public class ApacheCommonsExample {
        public static void main(String[] args) {
            List<String> list = Arrays.asList("Apple", "Banana", "Cherry");
            Iterator<String> iterator = IteratorUtils.unmodifiableIterator(list.iterator());
    
            while (iterator.hasNext()) {
                System.out.println(iterator.next());
            }
        }
    }

    📌 현재 방식: Stream을 이용해 불변 리스트를 만들 수 있음

    List<String> immutableList = List.of("Apple", "Banana", "Cherry");
    immutableList.forEach(System.out::println);

    하지만 IteratorUtils를 사용하면 기존 Iterator를 불변으로 만들 수 있다는 장점이 있음.


    3. Guava (Google Collections Library)

    1️⃣ 대표적인 예: com.google.common.collect.Iterators

    Google의 Guava 라이브러리는 Iterator를 보다 효율적으로 사용할 수 있도록 다양한 유틸리티를 제공한다.
    예를 들어, Iterators.filter()를 사용하면 특정 조건을 만족하는 요소만 걸러낼 수 있다.

    2️⃣ 활용 이유: Iterator 기반 필터링, 변환, 결합 등의 편의 기능 제공

    3️⃣ 사용 예 (필터링된 Iterator 생성)

    import com.google.common.collect.Iterators;
    import java.util.*;
    
    public class GuavaExample {
        public static void main(String[] args) {
            List<String> list = Arrays.asList("Apple", "Banana", "Cherry", "Avocado");
            Iterator<String> iterator = Iterators.filter(list.iterator(), item -> item.startsWith("A"));
    
            while (iterator.hasNext()) {
                System.out.println(iterator.next()); // Apple, Avocado
            }
        }
    }

    ✅ 현재 방식: Stream을 이용한 필터링

    list.stream()
        .filter(s -> s.startsWith("A"))
        .forEach(System.out::println);

    하지만 Iterator를 기반으로 처리해야 하는 경우에는 여전히 Guava의 Iterators가 유용함.


    4. Hibernate (org.hibernate.Query)

    1️⃣ 대표적인 예: Query.iterate()

    Hibernate에서는 대량의 데이터를 조회할 때 한꺼번에 로드하는 것이 아니라, 한 행씩 순회하면서 처리할 수 있도록 Iterator를 제공한다.
    이 방식은 메모리 절약 효과가 크다.

    2️⃣ 활용 이유: 대량의 데이터 처리 시 메모리 절약 효과

    3️⃣ 사용 예 (Hibernate Query.iterate() 사용)

    import org.hibernate.Session;
    import org.hibernate.query.Query;
    import java.util.Iterator;
    
    public class HibernateExample {
        public static void main(String[] args) {
            Session session = HibernateUtil.getSessionFactory().openSession();
            Query<String> query = session.createQuery("SELECT name FROM Product", String.class);
            Iterator<String> iterator = query.iterate();
    
            while (iterator.hasNext()) {
                System.out.println(iterator.next());
            }
    
            session.close();
        }
    }

    ✅ 현재 방식: Stream을 활용한 데이터베이스 조회 (Stream API + JPA)

    List<String> productNames = entityManager
        .createQuery("SELECT p.name FROM Product p", String.class)
        .getResultStream()
        .collect(Collectors.toList());
    
    productNames.forEach(System.out::println);

    하지만 대용량 데이터 처리에서는 여전히 iterate() 방식이 유용할 수 있음.


    5. Jackson (com.fasterxml.jackson.databind)

    1️⃣ 대표적인 예: JSON 데이터 스트리밍 (JsonParser)

    Jackson 라이브러리는 JSON 데이터를 다룰 때 Iterator 기반의 스트리밍 API를 제공한다.
    이를 통해 JSON을 한꺼번에 로드하지 않고, 한 요소씩 순차적으로 처리할 수 있다.

    2️⃣ 활용 이유: JSON을 한 요소씩 읽어 메모리 사용량을 줄일 수 있음

    3️⃣ 사용 예 (JsonParser를 활용한 JSON 순회)

    import com.fasterxml.jackson.core.JsonFactory;
    import com.fasterxml.jackson.core.JsonParser;
    import com.fasterxml.jackson.core.JsonToken;
    import java.io.StringReader;
    
    public class JacksonExample {
        public static void main(String[] args) throws Exception {
            String json = "[\"Apple\", \"Banana\", \"Cherry\"]";
    
            JsonFactory factory = new JsonFactory();
            JsonParser parser = factory.createParser(new StringReader(json));
    
            while (parser.nextToken() != JsonToken.END_ARRAY) {
                System.out.println(parser.getText());
            }
    
            parser.close();
        }
    }

    ✅ 현재 방식: JSON을 List로 변환 후 처리

    ObjectMapper objectMapper = new ObjectMapper();
    List<String> fruits = objectMapper.readValue(json, new TypeReference<List<String>>() {});
    
    fruits.forEach(System.out::println);

    하지만 대용량 JSON을 처리할 때는 여전히 JsonParser 기반의 Iterator 방식이 유리함.


    📌 정리

    라이브러리 주요 활용 대표적인 클래스/메서드 현재 권장 방식
    Java Collections Framework 컬렉션 순회 및 요소 제거 iterator() forEach()
    Apache Commons Collections Iterator 변환 및 조작 IteratorUtils.unmodifiableIterator() List.of() 활용
    Guava Iterator 기반 필터링 및 변환 Iterators.filter() Stream.filter()
    Hibernate 대용량 데이터 조회 Query.iterate() getResultStream()
    Jackson JSON 데이터 스트리밍 처리 JsonParser ObjectMapper.readValue()

    자바 8 이후 Stream API가 등장하면서 Iterator의 활용도가 줄었지만,
    대량 데이터 처리, ✅ 메모리 최적화, ✅ 컬렉션 변환 및 조작 등의 경우에는 여전히 Iterator 기반의 접근이 유용함. 🚀

    728x90
    반응형
    댓글