Iterator
컬렉션의 프레임워크에서 저장된 요소들을 읽기 위한 방법
종류:
- Iterator : 표준화한 인터페이스
- ListIterator : Iterator의 기능을 향상 시켰다.
- Enumeration : Iterator이전에 사용하던 인터페이스
1. Iterator Interface - List, Set
iterator의 경우 리스트의 순환에 사용한다. 따라서 리스트의 메서드에는 .iterator()로 Iterator의 인터페이스를 가져오는 메서드가 존재하므로, 해당 메서드를 사용하면 된다.
List<Integer> a = new ArrayList<>(Arrays.asList(111,222,333,444,555,666,777));
for (Iterator<Integer> iter = a.iterator(); iter.hasNext(); ) {
Integer element = iter.next();
System.out.println(element);
}
Iterator<Integer> iter = a.iterator();
while (iter.hasNext()) {
Integer element = iter.next();
}
이렇게 가능한 이유는 AbstractList와 Tree/Hash Set에서 각각의 iterator의 인스턴스를 가져오기 위해 구현해 놓았기 때문입니다.
List Iterator의 next()
public E next() {
checkForComodification();
try {
int i = cursor;
E next = get(i);
lastRet = i;
cursor = i + 1;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
Set Iterator의 next()
final class KeyIterator extends HashIterator
implements Iterator<K> {
public final K next() { return nextNode().key; }
}
Set의 경우 Map의 keySet에서 iterator를 뽑아와서 사용합니다.
2. Iterator Interface - Map
Map의 경우 순서가 아니라 Key와 Value를 통해 쌍으로 묶여있습니다. 따라서 직접 iterator를 가져오지는 못하고 keySet과 entrySet을 사용하여 가져와야 합니다.
final class KeyIterator extends HashIterator
implements Iterator<K> {
public final K next() { return nextNode().key; }
}
final class ValueIterator extends HashIterator
implements Iterator<V> {
public final V next() { return nextNode().value; }
}
final class EntryIterator extends HashIterator
implements Iterator<Map.Entry<K,V>> {
public final Map.Entry<K,V> next() { return nextNode(); }
}
또한 Set과 Map의 경우 List와 달리 각 요소간 순서가 유지되지 않기 때문에 순서가 매번 같지는 않다.
3. ListIterator Interface
Iterator의 경우 단방향으로 이동할 수 있지만, ListIterator는 양방향으로 이동이 가능하며, ArrayList나 LinkedList와 같이 List인터페이스를 구현한 컬렉션만 가능하다.
Iterator<Integer> iter = a.iterator();
Iterator<Integer> iter = a.listIterator();
listIterator는 기존 iterator와 동일하게 동작할 수 있다.
4. Remove()
iterator remove의 경우 기존 배열에서 데이터를 삭제했을 때와는 다르게 동작합니다.
먼저, iterator에서 알아야할 사항은 아래와 같습니다.
/**
* Index of element to be returned by subsequent call to next.
*/
int cursor = 0;
/**
* Index of element returned by most recent call to next or
* previous. Reset to -1 if this element is deleted by a call
* to remove.
*/
int lastRet = -1;
현재 위치와 마지막 위치 2개가 존재합니다.
remove 메서드
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
- lastRet값이 0보다 작으면 IllegalStateException()를 발생합니다.
- Remove메서드를 실행하게 되면, lastRet의 위치에 있는 값을 지우고
- 현재 위치를 이전 위치로 옮기고, 다시 lastRet을 -1로 만듭니다.
따라서 remove의 경우 단독으로 사용할 수 없고 Next메서드와 함께 사용해야 합니다. 그렇지 않으면 삭제가 된 후 lastRet의 값은 -1이 되어 계속 에러를 발생시키기 때문입니다.
'JAVA > 자바스터디' 카테고리의 다른 글
[자바 스터디] for vs foreach vs iterator (0) | 2023.01.28 |
---|---|
[자바스터디] Collection - Collections (0) | 2023.01.22 |
[자바스터디] Collection - List (0) | 2023.01.21 |
예외 처리 (0) | 2022.11.19 |
인터페이스 (0) | 2022.11.17 |