[Java] Iterator
Iterator는 컬렉션에 저장된 요소를 접근하는 데 사용되는 인터페이스이다. Iterator의 구버전은 Enumeration이고 Iterator의 기능을 확장시킨 것은 ListIterator이다.
Iterator는 Collection interface의 요소를 접근하기 위한 인터페이스라는 건 우리가 알고 있는 사실이다. 따라서 Iterator를 구현하는 iterator() 메서드는 Collection의 자식인 List와 Set에서도 사용할 수 있다.
Iterator의 메서드는 4가지가 있다.
public interface Iterator<E> {
boolean hasNext();
E next();
default void remove(){
throw new UnsupportedOperationException("remove");
}
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
여기서는 hasNext()와 next()를 다루어 보겠다.
Iterator를 사용하는 방법은 일단, Iterator 객체를 가지고 와야한다. Collection 인터페이스에 있는 iterator() 메서드를 이용해 Iterator 인터페이스를 구현할 수 있다. Collection의 자식인 List와 Set에도 iterator() 메서드는 존재한다.
Iterator<E> iterator();
Collection<Integer> list = new ArrayList<Integer>();
Iterator i = list.iterator(); //Iterator 인터페이스가 구현 됨.
Iterator는 Collection 인터페이스에 정의된 메서드이므로 ArrayList 대신 List인터페이스를 구현한 다른 컬렉션 클래스에 대해서도 위 코드는 동일하게 작동되고 수정할 필요가 없어진다.
이처럼 코드의 재사용성을 높이는 것이 Iterator의 장점이며 코드의 일관성을 유지, 재사용성 극대화로 객체지향 프로그래밍의 대표적인 예시와 장점이라고 볼 수 있다.
import java.util.*;
public class IteratorEx {
public static void main(String[] args) {
Collection<Integer> list = new ArrayList<Integer>();
list.add(3);
list.add(2);
list.add(1);
Iterator<Integer> i = list.iterator(); //Iterator 인터페이스가 구현 됨.
while(i.hasNext()) { //hasNext()로 모든 요소를 순회한다.
System.out.print(i.next()+" "); //next() 메서드로 값을 가지고 온다.
}
}
}
메서드 | 기능 |
boolean hasNext() | 해당 이터레이션(iteration)이 다음 요소를 가지고 있으면 true를 반환하고, 더 이상 다음 요소를 가지고 있지 않으면 false를 반환함. |
E next() | 이터레이션(iteration)의 다음 요소를 반환함. |
요소가 몇개가 있는지 확실하지 않을 수 있으므로 반복문(while)을 이용해 hasNext() 메서드를 사용하여 모든 요소를 순회하게 한다. hasNext()메서드 return값이 true이면 next() 메서드로 요소를 가지고 온다.
Iterator 인터페이스는 일회성이다. hasNext()로 모든 요소를 순회하고 false를 반환하면 다시 재사용할 수 없다.
Iterator<Integer> it = list.iterator();
while(it.hasNext()) {
System.out.print(it.next()+" ");
}
while(it.hasNext()) {
System.out.print(it.next()+" ");
}
이런식으로 사용된 Iterator 인터페이스를 또다시 사용하면 false를 반환하므로 2번째 반복문은 작동하지 않는다. 참조 변수 it가 가리키는 객체는 첫 번째 while 문으로부터 hasNext()는 false로 되었기 때문이다. 하나의 객체에서 while문 2개를 사용하는 것이 아닌 새로운 객체를 또 만들어서 각자 다른 반복문을 사용해야 한다.
Iterator<Integer> it = list.iterator();
while(it.hasNext()) {
System.out.print(it.next()+" ");
}
System.out.println();
Iterator<Integer> it2 = list.iterator();
while(it2.hasNext()) {
System.out.print(it2.next()+" ");
}
List<Integer> list = new ArrayList<Integer>();
list.add(3);
list.add(2);
list.add(1);
for(int i=0; i<list.size();i++) {
System.out.print(list.get(i)+" ");
}
Iterator를 사용하지 않고 list의 요소들을 전부 접근할 수 있다. 하지만 개발자가 성능의 문제로 ArrayList가 아닌 HashSet으로 자료구조를 바꿨다고 가정해보자.
Set<Integer> list = new HashSet<Integer>();
list.add(3);
list.add(2);
list.add(1);
for(int i=0; i<list.size();i++) {
System.out.print(list.get(i)+" ");
}
Set인터페이스에도 존재하는 add메서드로 추가는 가능하지만 반복문 부분에서 에러가 발생한다. get()메서드는 Set에 존재하지 않는다. 즉, 반복문 부분은 쓸모없어진 코드가 된 것이다.
Collection을 바꾸면 바꿀 Collection에는 존재하지 않는 메서드들이 있을 것이다. 존재하지 않는 메서드를 사용하면 당연히 에러가 발생하며, 일일히 코드들을 다시 봐야 하는 상황이 발생한다.
이 문제를 해결하기 위해 Iterator를 사용하는 것이다. Iterator는 Collection 자식들 모두 호환이 가능한 인터페이스이므로 Collection을 바꾸더라도 요소를 접근하는 코드는 바뀔 필요가 없어진다.
Map인터페이스를 구현한 컬렉션 클래스는 iterator()를 직접 호출할 수 없다. interator()를 사용할 수 있는 Set인터페이스 형태로 얻어 온 후 iterator()를 사용할 수 있다. (keySet(), entrySet() 사용해서 Set 형태로 변환)
Map map = new HashMap();
Iterator it = map.entrySet().iterator();
Iterator의 구버전 Enumeration의 사용법은 Iterator와 차이점이 별루 없다.
hasMoreElements()로 요소 순회 (검색)
nextElement()로 요소 값 가지고 오기
List<Integer> list = new LinkedList<Integer>();
list.add(3);
list.add(2);
list.add(1);
Enumeration<Integer> en = Collections.enumeration(list);
while(en.hasMoreElements()) {
System.out.print(en.nextElement()+" ");
}
http://www.tcpschool.com/java/java_collectionFramework_iterator
코딩교육 티씨피스쿨
4차산업혁명, 코딩교육, 소프트웨어교육, 코딩기초, SW코딩, 기초코딩부터 자바 파이썬 등
tcpschool.com