List의 내부구조 탐험 : Iterator
필자의 블로그 [커리어리 글을 작성하는 것이 다소 익숙하지 않기에, 아래 블로그로 가면 가독성이 더욱 좋을 것 입니다.] https://blog.naver.com/PostView.naver?blogId=gomets_journey&logNo=223319080943&categoryNo=28&parentCategoryNo=0&viewDate=¤tPage=1&postListTopCurrentPage=1&from=postList&userTopListOpen=true&userTopListCount=5&userTopListManageOpen=false&userTopListCurrentPage=1 for문과 forEach문은 둘 다 반복문이지만, 몇 가지 차이점이 있다. 그것부터 우선 알아보도록 하자. for문 1. 일반적인 구조 for (초기화; 조건; 증감) { // 반복 수행될 코드 } 2. 인덱스 기반 순회 * for문은 배열이나 리스트 등과 같은 자료구조를 인덱스를 이용하여 순회할 때 주로 사용된다. 3. 모든 유형의 반복 가능한 객체에 적용 가능 * for문은 모든 반복 가능한 객체에 적용할 수 있다. forEach문 1. 컬렉션 전용 구조 * forEach문은 Java 8부터 추가된 기능으로, 컬렉션과 스트림을 순회할 때 사용된다. 2. 람다 표현식 사용 * forEach문은 함수형 프로그램잉의 개념을 도입하여, 람다 표현식을 이용한 간결한 코드 작성을 가능하게 한다. 3. 내부 반복 * forEach문은 컬렉션 내부에서 자동으로 반복하며, 개발자는 반복 로직을 명시적으로 작성하지 않아도 된다. 이는 코드를 간결하게 만들고, 개발자가 실수로 루프를 종료하는 등의 문제를 방지한다. 4. 병렬 처리 지원 * Java 8부터 제공되는 parallelStream()과 함께 사용하면, forEach문은 내부적으로 병렬 처리를 지원할 수 있다. // for문 List list = Arrays.asList("A", "B", "C"); for (int i = 0; i list = Arrays.asList("A", "B", "C"); list.forEach(item -> System.out.println(item)); forEach 문의 단점 * loop의 시작과 끝을 일반 for문과 다르게 지정할 수 없다. * 순회 중 원소의 변경 및 삭제가 불가능하다. * 원하는 인덱스를 직접 지정하여 사용할 수 없다. * 만약 get(i)처럼 인덱스를 필요로 한다면, 기존의 일반적인 for문을 사용해야 한다. 우리는 위에서 forEach문은 순회 중 원소의 변경 및 삭제가 불가능하다는 것을 알게되었다. 하지만 Iterator는 remove() 메서드를 사용하여 원소를 삭제할 수 있다. 아래는 리스트에서 요소를 삭제하는 예시이다. import java.util.Arrays; import java.util.Iterator; import java.util.List; public class Example { public static void main(String[] args) { List list = Arrays.asList("A", "B", "C"); Iterator iterator = list.iterator(); while (iterator.hasNext()) { String item = iterator.next(); System.out.println(item); // remove()를 사용하여 현재 요소를 삭제 iterator.remove(); } System.out.println("List after removal: " + list); } } 위 예제에서 iterator.remove()를 호출하면 현재 가리키고 있는 요소가 삭제된다. 주의할 점은 remove() 메서드를 호출하기 전에 반드시 next() 메서드를 호출해야 하며, 한 번의 next()에 대해 한 번의 remove()만 호출 가능하다. 또한 remove() 메서드를 사용할 수 있는 컬렉션에서만 사용할 수 있다. 위 코드에서는 Arrays.asList()를 이용하여 생성한 List 객체에서 remove()를 사용하고 있다. 그러면 여기서 의문점이 생길 것이다. 왜 굳이 Iterator로 순회 중 원소를 삭제하는 것일까 for문을 사용하여 순회 중 원소를 삭제하는 것이 더 간단하지 않을까하는 것이다. 아래는 예제 코드이다 import java.util.ArrayList; import java.util.List; public class Example { public static void main(String[] args) { List list = new ArrayList(); list.add("Apple"); list.add("Banana"); list.add("Cherry"); list.add("Date"); list.add("Orange"); // 특정 조건을 만족하는 원소 삭제 for (int i = 0; i set = new HashSet(); set.add("A"); set.add("B"); set.add("C"); for (String item : set) { System.out.println(item); } } } Iterator를 사용하여 HashSet을 순회 import java.util.HashSet; import java.util.Iterator; import java.util.Set; public class Example { public static void main(String[] args) { Set set = new HashSet(); set.add("A"); set.add("B"); set.add("C"); Iterator iterator = set.iterator(); while (iterator.hasNext()) { String item = iterator.next(); System.out.println(item); } } } 여기서 for(String item : set)는 Set을 순회하기 위한 향상된 for문(forEach문)이며 내부적으로 Iterator를 사용하여 구현된다. (Java 5부터 향상된 for문을 통해 Set과 같은 Iterable 객체를 좀 더 간결하게 순회할 수 있게 되었다.) 다만 Iterator를 사용하려면 매번 Iterator 타입의 변수 생성, 초기화를 해야한다. 그리고 반복문을 통해 Iterator의 내부에 있는 커서를 옮겨서 컬렉션 아이템을 탐색할 수 있기에 Iterator 타입 객체를 사용하여 아이템을 탐색할 경우 기본 코드가 많아진다. 따라서 내가 사용하고자 하는 목적에 맞게 적절한 것(for문 / forEach문 / Iterator)를 사용하면 될 것이다.