[기본 개념] 6 | (1.5) Iterator, ListIterator, Enumeration
1 컬렉션 프레임웍의 핵심 인터페이스
2 ArrayList
3 LinkedList
4 Stack과 Queue
5> Iterator, Listlterator, Enumeration
6 Arrays
7 Comparator와 Comparable
8 HashSet
9 TreeSet
10 HashMap과 Hashtable
11 TreeMap
12 Properties
13 Collections
14 컬렉션 클래스 정리 & 요약
5. Iterator, Listlterator, Enumeration
Iterator, ListIterator, Enumeration은 모두 컬렉션에 저장된 요소를 접근하는 데 사용되는 인스턴스이다. Enumeration은 Iterator의 구버전이며, ListIterator는 Iterator의 기능을 향상한 것이다.
Iterator
Iterator인스턴스는 컬렉션에 저장된 각 요소에 접근하는 기능을 가졌다. Collection인터페이스는 'Iterator(Iterator를 구현한 클래스의 인스턴스)'를 반환하는 iterator( )를 정의한다.
Iterator( )는 Collection인터페이스에 정의된 메서드이므로 자손인 List와 Set에도 포함되어 있다.
컬렉션 클래스에 대해 iterator( )를 호출하여 Iterator를 얻은 다음 while문을 사용해서 컬렉션 클래스의 요소를 읽어올 수 있다. Iterator를 이용해서 컬렉션의 요소를 읽어오는 방법을 표준화했기 때문에 코드의 재사용성을 높였다.
Map인터페이스는 iterator( )를 직접 호출할 수 없고, keySet( )이나 entrySet( )같은 메서드로 키와 값을 따로 Set의 형태로 얻어온 후 다시 iterator( )를 호출해야 Iterator를 얻을 수 있다.
Map map = new HashMap( ) ;
. . .
Iterator it = map.entrySet( ).iterator( ) ;
List클래스들은 저장 순서를 유지하기 때문에 Iterator를 이용해서 읽어온 결과 역시 저장 순서가 동일하지만, Set클래스들은 각 요소간의 순서가 유지되지 않기 때문에 Iterator를 이용하면 저장순서가 같지 않다.
ListIterator와 Enumeration
Enumeration은 Iterator의 구버전이기 때문에 호환을 위하는 것이 아니면 Iterator를 사용하는 것이 좋다.
ListIterator는 Iterator를 상속받아서 기능을 추가한 것으로, Iterator는 단방향으로만 이동할 수 있는데 ListIterator는 양방향으로 이동이 가능하다. 다만, List인터페이스를 구현한 컬렉션에서만 사용 가능하다.
Enumeration Iterator의 구버전
ListIterator Iterator에 양방향 조회 기능 추가 (List를 구현한 경우에만)
예제/ListIteratorEx1.java
import java.util.*;
public class ListIteratorEx1 {
public static void main(String[] args) {
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.print(it.next()); // 순방향
System.out.println();
while (it.hasPrevious()) System.out.print(it.previous()); // 역방향
}
}
실행결과
12345
54321
Iterator는 단방향으로만 이동하기 때문에 마지막 요소에 다다르면 더 이상 사용할 수 없지만, ListIterator는 양방향으로 이동하기 때문에 각 요소 간의 이동이 자유롭다.
이동하기 전에 반드시 hasNext( )나 hasPrevious( )를 호출해서 이동할 수 있는지 확인해야 한다.
ListIterator의 메서드들 중에서 Iterator인터페이스로부터 상속받은 메서드는 추상메서드라 메서드의 몸통을 반드시 만들어야 한다. 단순히 구현하는 것보다 예외를 던지면 메서드를 호출하는 쪽에서 구현되지 않은 기능이라는 것을 알릴 수 있다.
예제/MyVector2.java
import java.util.*;
public class MyVector2 extends MyVector implements Iterator {
int cursor = 0;
int lastRet = -1;
public MyVector2(int capacity) {
super(capacity);
}
public MyVector2() {
this(10);
}
public String toString() {
String tmp = "";
Iterator it = iterator();
for (int i = 0; it.hasNext(); i++) {
if (i != 0) tmp += ", ";
tmp += it.next(); // tmp += next().toString();
}
return "[" + tmp + "]";
}
public Iterator iterator() {
cursor = 0; // cursor와 lastRet을 초기화 한다.
lastRet = -1;
return this;
}
public boolean hasNext() {
return cursor != size();
}
public Object next() {
Object next = get(cursor);
lastRet = cursor++;
return next;
}
public void remove() {
// 더이상 삭제할 것이 없으면 IlleaglStateException를 발생시킨다.
if (lastRet == -1) {
throw new IllegalStateException();
} else {
remove(lastRet);
cursor--; // 삭제 후에 cursor의 위치를 감소시킨다.
lastRet = -1; // lastRet의 값을 초기화한다.
}
}
}
cursor는 앞으로 읽어올 요소의 위치를 저장하는 데 사용되고, lastRet는 마지막으로 읽어온 요소의 위치(index)를 저장하는 데 사용된다.
그래서 lastRet은 cursor보다 항상 1이 작은 값이 저장되고 remove( )를 호출하면 lastRet에 저장된 값의 위치에 있는 요소를 삭제하고 lastRet의 값을 -1로 초기화한다.
만약 next( )를 호출하지 않고 remove( )를 호출하면 IllegalStateException이 발생한다. remove( )는 next( )로 읽어온 객체를 삭제하는 것이기 때문에 remove( )를 호출하기 전에는 반드시 next( )가 호출된 상태여야 한다.
1 만일 0 ~ 4의 값이 저장되어 있는 MyVecter2의 Iterator를 얻어왔다면 다음 그림의 상태일 것이다.
<---- lastRet = -1 | |
0 | <---- cursor = 0 |
1 | |
2 | |
3 | |
4 |
2 그리고 next( )를 두 번 호출하면 다음과 같은 그림이 될 것이다. 첫 번째 요소인 0을 읽고 두 번째 요소인 1까지 읽어온 상태이다.
<---- lastRet = -1 | |
0 | <---- cursor = 0 |
1 | |
2 | |
3 | |
4 | |
▼ it.next( ) | |
0 | <---- lastRet = 0 |
1 | <---- cursor = 1 |
2 | |
3 | |
4 | |
▼ it.next( ) | |
0 | |
1 | <---- lastRet = 1 |
2 | <---- cursor = 2 |
3 | |
4 |
3 remove( )를 호출하면, 마지막으로 읽어온 요소 1이 삭제된다. 이때 lastRet의 값은 -1로 초기화되고 cursor의 값은 1 감소된다. 데이터가 삭제되어 다른 데이터가 한 자리씩 이동했기 때문에 cursor의 위치도 이동돼야 하기 때문이다.
0 | |
1 | <---- lastRet = 1 |
2 | <---- cursor = 2 |
3 | |
4 | |
▼ it.remove( ) | |
<---- lastRet = -1 | |
0 | |
2 | <---- cursor = 1 |
3 | |
4 |
출처 | Java의 정석 (남궁 성)
'💠프로그래밍 언어 > Java' 카테고리의 다른 글
[기본 개념] 6 | (1.7) HashSet (0) | 2021.12.03 |
---|---|
[기본 개념] 6 | (1.6) Arrays, Comparator, Comparable (0) | 2021.12.03 |
[기본 개념] 6 | (1.4) Stack, Queue (0) | 2021.12.02 |
[기본 개념] 6 | (1.3) LinkedList (0) | 2021.12.02 |
[기본 개념] 6 | (1.2) ArrayList (0) | 2021.12.02 |