"Iterator, ListIterator, Enumeration"
"컬렉션에 저장된 데이터를 접근하는데 사용되는 인터페이스"
Enumeration은 Iterator의 구버전
ListIterator는 Iterator의 접근성을 향산시킨 것 (단방향 -> 양방향)
1. Iterator 인터페이스의 메서드
| 메서드 | 설명 |
| boolean hasNext( ) | 읽어 올 요소가 남아있는지 확인한다. 있으면 true, 없으면 false 반환 |
| Object next( ) | 다음 요소를 읽어 온다. next( )를 호출하기 전에 hasNext( )를 먼저 호출해서 읽어 올 요소가 있는지 확인하는 것이 안전하다. |
| void remove( ) | next( )로 읽어 온 요소를 삭제한다. next( )를 먼저 호출하고 remove( )를 호출해야 한다. (선택적 기능) |
| void forEachRemaining(Consumer<? super E> action) | 컬렉션에 남아있는 요소들에 대해 지정된 작업(action)을 수행한다. 람다식을 사용하는 디폴트 메서드, |
2. Enumeration 인터페이스의 메서드
| 메서드 | 설명 |
| boolean hasMoreElements( ) | 읽어 올 요소가 남아있는지 확인한다. 있으면 true, 없으면 false 반환, Iterator의 hasNext( )와 같다. |
| Object nextElements( ) | 다음 요소를 읽어 온다. nextElements( )를 호출하기 전에 hasMoreElements( )를 먼저 호출해서 읽어 올 요소가 있는지 확인하는 것이 안전하다. Iterator의 next( )와 같다. |
"Iterator는 왜 필요할까?"
컬렉션에는 List, Set, Map 다양한 종류의 컬렉션이 있는데, 각 컬렉션 마다 구조가 다르다.
==> 요소들을 읽어오는 방법이 다 다르다.
List > ArrayList, LinkedList 등등..
Set > TreeSet 등등..
Map > HashMap 등등..
이렇게 각자 다른 방식의 컬렉션들의 저장된 요소를 읽어오는 방법을 표준화한것이 Iterator
boolean hasNext( ) >> 읽어 올 요소가 있는지 확인
Object next( ) >> 다음 요소를 읽어옴
Iterator 사용방법
Iterator 메서드는 Collection 인터페이스에 정의되어 있는데,
Collection 인터페이스의 자손인 List와 Set이 모두 가지고 있는 메서드이다.
컬렉션에 Iterator( )를 호출해서 Iterator를 구현한 객체를 얻어서 사용한다.
List list = new ArrayList( );
Iterator it = list.Iterator( ); >> Iterator 메서드 호출
이렇게 메서드를 호출하면 Iterator( ); 메서드가 객체를 반환해주기 때문에,
Iterator it >> 객체를 얻을 수 있다.
while(it.hasNext()){
System.out.println(it.next());
}
이런식으로 hasNext( )를 통해 읽어 올 요소가 있는지 먼저 확인해주고, next( )로 요소를 읽어오면 된다.
계속 반복해서 요소를 읽어오다가 만약 읽어 올 요소가 더 이상 없으면 hasNext( )가 false를 반환해서 while문이 멈추는 원리이다.
*** 주의사항 : Iterator는 "1회용"이다. 만약 Iterator를 얻어와서 읽어오는데 이미 사용을 했는데, 다음 명령문에서 다시 읽어올려면 Iterator를 다시 얻어와야한다.
예시 코드
public class Ex11_5 {
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);
Iterator it = list.iterator();
while (it.hasNext()) {
Object obj = it.next();
System.out.println(obj);
}
//TODO Iterator는 1회용이라 다쓰고나면 다시 얻어와야 한다.
it = list.iterator(); //TODO 새로운 Iterator객체를 얻는다.
while (it.hasNext()) {
Object obj = it.next();
System.out.println(obj);
}
}
}
출력해보면
1번 while문:
1
2
3
4
5
2번 while문:
1
2
3
4
5
while문이 2개가 다 출력된 것을 확인할 수 있다.
Iterator it = list.iterator(); >> 1번째 Iterator를 얻어옴
it = list.iterator(); >> 2번째 Iterator를 얻어옴
Iterator의 장점
ArrayList list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
Iterator it = list.iterator();
System.out.println("1번 while문: ");
while (it.hasNext()) {
Object obj = it.next();
System.out.println(obj);
}
for(int i = 0; i < list.size(); i++){
Object obj = list.get(i);
System.out.println(obj);
}
여기서 get메서드를 활용하여 for문으로 사용해도 Iterator를 사용한 것과 같은 결과가 출력된다.
하지만 만약 ArrayList를 HashSet으로 바꿧을 때를 생각해보자,
HashSet list = new HashSet();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
Iterator it = list.iterator();
System.out.println("1번 while문: ");
while (it.hasNext()) {
Object obj = it.next();
System.out.println(obj);
}
for(int i = 0; i < list.size(); i++){
Object obj = list.get(i);
System.out.println(obj);
}
HashSet도 Collection인터페이스의 자손이여서 Iterator는 사용이 가능하다.
하지만 문제가 HashSet에는 get 메서드가 없기 때문에 for문에서 에러가 발생한다.
Iterator는 List나 Set이나 다 똑같이 동작하게 표준화 되어 있기 때문에,
List를 쓰다가 Set으로 바꿔도 코드를 건드리지 않아도 된다는 장점이 있고, 사용하기 편리하다.
다형성
HashSet은 Set인터페이스를 구현했고, Set은 Collection의 자손이다.
그래서 Collection list = new HashSet( ); 이렇게 사용할 수 있다.
HashSet list = new HashSet( ); 이렇게 사용할 수도 있지만, 나중에 HashSet을 TreeSet 같은 다른걸로 바꾸게되면
참조변수 타입도 바꿔줘야 하기 때문에, 아래 코드들을 전부 검토해야한다.
하지만,
Collection list = new HashSet( );
Collection list = new TreeSet( );
이렇게 참조변수 타입을 조상타입으로 해놓으면 실제 구현한 클래스는 달라도, 사용한 멤버의 갯수는 똑같아진다.
>> 참조변수가 조상 타입이면, TreeSet이나 HashSet클래스에 공통되어 있는 멤버들만 사용
실제 객체가 HashSet이나 TreeSet이여도 Collection이라는 리모콘에 있는 것만 사용이 가능하다.
>> Collection 인터페이스에 정의된 메서드 외에는 쓰지 않았다는 확신이 생김
"Map"
Map에는 iterator( ) 가 없다.
Map은 Collection 인터페이스의 자손이 아니기 때문이다.
그래서 keySet(), entrySet(), values() 메서드들을 이용해야 하는데,
keySet(), entrySet() >> 반환 타입 Set
values() >> 반환 타입 Collection
entry >> (key, value) 한 쌍을 의미
반환 타입이 Set, Collection이므로, iterator를 가지고 있다.
Map에서 Iterator를 바로 가지고 올 수 없으니, 메서드를 이용해서 Set이나 Collection을 얻은 다음,
거기에 Iterator를 호출하여 사용한다.
Map map = new HashMap();
Iterator it = map.entrySet().iterator();
이것을 쪼개서 써보면
Set eSet = map.entrySet();
Iterator it = eSet.iterator();
이렇게 된다.