Iterator, ListIterator, Enumeration은 모두 컬렉션에 저장된 요소를 접근하는데 사용된다.
Enumeration은 Iterator의 구버전, ListIterator은 Iterator의 기능을 향상시켰다.
컬렉션 프레임워크에서는 컬렉션에 저장된 요소들을 읽어오는 방법을 표준화하였다. 그것이 Iterator 인터페이스이다.iterator()
는 Collection 인터페이스에 정의된 메서드이다.
이 메서드는 Iterator를 구현한 클래스의 인스턴스를 반환한다.
public Interface Collection {
//...
public Iterator iterator();
//...
}
Collection 인터페이스에 속한 List와 Set에는 반드시 iterator()
가 구현되어야 한다(인터페이스니까). 따라서 List 와 Set에서 각 특징에 맞게 구현되어 있다.
코드는 다음과 같다.
Collection c = new ArrayList();
Iterator it = c.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
Map인터페이스를 구현한 컬렉션 클래스는 Key(키)와 값(Value) 를 쌍으로 구현하고 있으므로, iterator()
를 직접 호출할 수 없다. 대신에 keySet()
이나 entrySet()
으로 키와 값들을 Set형태로 불러오고, 다시 Iterator()을 호출하는 형태로 요소들을 읽어올 수 있다.
Iterator에 양방향 조회 기능을 추가한 Iterator이다. Collection 인터페이스에 속한 Set, List에 사용되는 Iterator와 달리, ListIterator는 List를 구현한 경우에만 사용이 가능하다.
양방향이므로, hasNext()
, hasPrevious()
같은 메서드가 공존한다.
Iterator의 remove()
메서드는 단독으로 사용될 수 없다. 반드시 next()
나 previous()
이후에 사용해야 한다. 이는 특정 위치에 존재하는 요소를 삭제하는 것이 아니라 읽어온 요소를 삭제하는 것이기 때문이다.
기본적으로 Iterator에는 cursor(앞으로 읽어올 요소위 위치), lastReturn(마지막으로 읽어온 요소의 위치) 두가지의 포인터 역할이 존재한다.
lastReturn은 항상 cursor보다 1작고, remove()
호출 시에, lastReturn은 -1값이 되어, 제거하고 나면 읽어온 요소가 초기화 된다. 따라서 remove()
메서드는 반드시 요소를 읽고난 후에 사용되어야 한다는 것이다.
코드로 보면 아래와 같다.
public void remove(){
if(lastRet == -1){
throw new IllegalStateException("읽어온 요소가 없습니다.");
} else {
remove(lastRet);
cursor--;
lastRet = -1;
}
}
이를 그림으로 살펴보자.
만일 이러한 0,1,2,3,4 순서로 저장된 List 가 있다고 하자. 그러면 List의 Iterator를 얻어오면, 초기 상태는 다음과 같다. 그다음 next를 두번 실행시켜 보자.
이 다음에 remove()를 시키면 다음과 같다.
잘 기억해두자!