Iterator, ListIterator, Enumeration은 모두 컬렉션에 저장된 요소를 접근하는데 사용되는 인터페이스이다. Enumeration은 Iterator의 구버젼이며, ListIterator는 Iterator의 기능을 향상 시킨 것이다.
컬렉션 프레임워크에서는 컬렉션에 저장된 요소들을 읽어오는 방법을 표준화하였다. 컬렉션에 저장된 각 요소에 접근하는 기능을 가진 Iterator 인터페이스를 정의하고, Collection 인터페이스에는 'Iterator(Iterator를 구현한 클래스의 인스턴스)'를 반환하는 iterator()를 정의하고 있다.
iterator()는 Collection인터페이스에 정의된 메서드이므로 Collection 인터페이스의 자손인 List와 Set에도 포함되어 있다. 그래서 List나 Set 인터페이스를 구현하는 컬렉션은 iterator()가 각 컬렉션의 특징의 알맞게 작성되어 있다. 컬렉선 클래스에 대해 iterator()를 호출하여 Iterator를 얻은 다음 반복문, 주로 while문을 사용해서 컬렉션 클래스의 요소들을 읽어 올 수 있다.
boolean hasNext() : 읽어 올 요소가 남아있는지 확인한다. 있으면 true, 없으면 false를 반환한다.
Object next() : 다음 요소를 읽어 온다. next()를 호출하기 전에 hasNext()를 호출해서 읽어 올 요소가 있는지 확인하는 것이 안전하다.
void remove() : next()로 읽어 온 요소를 삭제한다. next()를 호출한 다음에 remove()를 호출해야한다. (선택적 기능)
public void iteratorTest() {
ArrayList list = new ArrayList();
list.add("2");
list.add("1");
list.add("3");
list.add("4");
list.add("5");
Iterator it = list.iterator();
while (it.hasNext()) {
Object obj = it.next();
System.out.println(obj);
}
}
실행 결과
2
1
3
4
5
ArrayList대신 Collection 인터페이스를 구현한 다른 컬렉션 클래스에 대해서도 이와 동일한 코드를 사용할 수 있다. 첫 줄에서 ArrayList대신 Collection 인터페이스를 구현한 다른 컬렉션 클래스의 객체를 생성하도록 변경하기만 하면 된다.
Iterator를 이용해서 컬렉션의 요소를 읽어오는 방법을 표준화했기 때문에 이처럼 코드의 재사용성을 높이는 것이 가능한 것이다. 이처럼 공통 인터페이스를 정의해서 표준을 정의하고 구현하여 표준을 따르도록 함으로써 코드의 일관성을 유지하여 재사용성을 극대화하는 것이 객체지향 프로그래밍의 중요한 목적 중의 하나이다.
Q. 참조변수의 타입을 ArrayList타입이 아니라 Collection타입으로 한 이유는?
A. Collection에 없고 ArrayList에만 있는 메서드를 사용하는게 아니라면, Collection타입의 참조변수로 선언하는 것이 좋습니다. 만일 Collection 인터페이스를 구현한 다른 클래스, 예를들어 LinkedList로 바꿔야 한다면 선언문 하나만 변경하면 나머지 코드는 검토하지 않아도 됩니다. 참조변수 타입이 Collection이므로 Collection에 정의되지 않은 메서드는 사용되지 않았을 것이 확실하니까요. 그러나 참조변수 타입을 ArrayList로 했다면, 선언문 이후의 문장들을 검토해야 합니다. Collection에 정의되지 않은 메서드를 호출했을 수 있기 때문입니다.
Map인터페이스를 구현한 컬렉션 클래스는 키(key)와 값(value)을 쌍으로 저장하고 있기 때문에 iterator()를 직접 호출할 수 없고, 그 대신 keySet()이나 entrySet()과 같은 메서드를 통해서 키와 값을 각각 따로 Set의 형태로 얻어 온 후에 다시 iterator()를 호출해야 Iterator를 얻을 수 있다.
Enumeration은 컬렉션 프레임워크가 만들어지기 이전에 사용하던 것으로 Iterator의 구버젼이라고 생각하면 된다. 이전 버전으로 작성된 소스와의 호환을 위해서 남겨 두고 있을뿐이므로 가능하면 Enumeration 대신 Iterator를 사용하자.
ListIterator는 Iterator를 상속 받아서 기능을 추가한 것으로, 컬렉션의 요소에 접근할 때 Iterator는 단방향으로만 이동할 수 있는 데 반해 ListIterator는 양방향으로의 이동이 가능하다. 다만 ArrayList나 LinkedList와 같이 List 인터페이스를 구현한 컬렉션에서만 사용할 수 있다.
Enumeration : Iterator의 구버젼
ListIterator : Iterator에 양방향 조회기능추가(List를 구현한 경우만 사용가능)
ListIterator는 Iterator에 이전방향으로의 접근기능을 추가한 것일 뿐이다.
public void listIteratorTest() {
ArrayList list = new ArrayList();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
list.add("5");
ListIterator it = list.listIterator();
while (it.hasNext()) {
System.out.println(it.next());
}
System.out.println();
while (it.hasPrevious()) {
System.out.println(it.previous());
}
System.out.println();
}
실행 결과
1
2
3
4
5
5
4
3
2
1