Java/Java Study

[Collections Framework] Iterator 와 메서드 iterator

모모토 2021. 5. 27. 12:25
반응형

 갑작스럽게, 이 포스팅을 하는 이유는, 메서드 iterator()에 대한 설명이 잘 이해가 가지 않아 정리할 겸 나처럼 헤매는 사람이 혹시라도 있을 수 있을까 봐이다. (그리고 내가 또 까먹을까 봐)

 

● Iterator

 

Iterator는 컬렉션에 저장된 요소들에 대한 접근을  표준화하였다.

Iterator는 인터페이스이고 이 인터페이스에는 hasNext, remove, next 3개의 추상 메서드가 존재한다.

 

hasNext - 불러올 다음 요소가 있는지 확인한다. 존재한다면 true를 반환

 

next - 순차적으로 요소를 불러온다.

 

remove - next로 불러온 요소를 제거한다.(next 없이 단독으로 쓰일 수 없다.)


그리고 Collection에는 이 Iterator 인터페이스를 구현한 클래스의 객체를 반환하라는 추상 메서드 iterator가 있다.

List와 Set은 collection을 상속받기에 따라서 ArrayList, LinkedList 같은 컬렉션 클래스는

당연히 iterator() 메서드를 구현한다. ArrayList에 구현된 iterator메서드의 내용을 보면 다음과 같다.

 

public Iterator<E> iterator() {
    return new Itr();
}

private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;

        Itr() {}

        public boolean hasNext() {
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        @Override
        @SuppressWarnings("unchecked")
        public void forEachRemaining(Consumer<? super E> consumer) {
            Objects.requireNonNull(consumer);
            final int size = ArrayList.this.size;
            int i = cursor;
            if (i >= size) {
                return;
            }
            final Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length) {
                throw new ConcurrentModificationException();
            }
            while (i != size && modCount == expectedModCount) {
                consumer.accept((E) elementData[i++]);
            }
            // update once at end of iteration to reduce heap write traffic
            cursor = i;
            lastRet = i - 1;
            checkForComodification();
        }

        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

 

iterator 메서드는 결과적으로 객체 new Itr()을 반환하는데 객체 Itr 은 Iterator를 구현하였으므로 객체 Itr을 이용하여 next, hasNext, remove 등의 메서드를 사용할 수 있을 것이다.

 

메서드 iterator()를 통하여 요소에 접근하는 코드는 다음과 같다.

 

Collection c= new ArrayList(10);

Iterator it = c.iterator();
// Iterator it = new Itr();

while(it.hasNext()){
	System.out.println(it.next());    
   }

 

그렇다면 iterator를 쓰는 목적은 무엇일까?

 

만약 우리가 ArrayList 말고 성능의 개선이나 다른 이유로 컬렉션 클래스를 바꿔줘야 할 경우

 

선언 부만 바꿔주면 다른 코드는 검사하지 않아도 된다는 장점이 있기 때문이다. 

 

Collection c= new LinkedList;

Iterator it = c.iterator();
// Iterator it = new Itr();

while(it.hasNext()){
	System.out.println(it.next());
    }

 

이때 주의해야 할 점은 Collection 타입으로 참조 변수를 만들어 컬렉션 클래스의 인스턴스를 생성해야 한다는 것이다.

 

다형성의 규칙에 의하여 Collection 인터페이스에 속한 메서드만 사용할 수 있게 되므로, 컬렉션 클래스를 바꾸어도 따로 수정해야 할 코드가 생기지 않게 되는 것이다.

 


처음엔 ' Iterator it = c.iterator(); ' 이 부분이 이해가 안 되어서 결국 코드를 찾아보면서 iterator의 쓰임을 이해하게 되었다.