Javaコレクション:反復器(Iterator,Iterable)

19344 ワード

Iteratorインタフェース
public interface Iterator<E> {



    boolean hasNext();



    E next();



    void remove();

}

要素にアクセスする前にhasNextを使用して要素が存在するかどうかを判断する必要があります.またnext操作で取得した場合は、hasNext検出を行わずにnext操作を直接使用し、末尾に達するとNoSuchElement異常が放出されます.
Iteratorのremove操作
JDKコードを見るのは久しぶりで、今日Java Coreを見て反復器の中の注意点を見て、意外にも少しも思い出せませんでした.まず、次のコードを参照してください.
        Iterator<String> iter = list.iterator();

        String s = iter.next();

        iter.remove();

では、ここでiter.remove()が削除した要素はどの要素で、削除したのはリストの最初の要素で、一般的には反復器が前回next()で返した要素です.次のコードもあります.
        Iterator<String> iter = list.iterator();

        String s = iter.next();

        iter.remove();

        iter.remove();

実際に実行すると、java.lang.IllegalStateException異常、すなわち、removeのたびに対応するnextがあるはずですが、実は2つのペアで、removeのはnextが返す要素です.
AbstractListのソースコードから、Iteratorの基本的な実装がわかります.
 1 private class Itr implements Iterator<E> {

 2         /**

 3          * Index of element to be returned by subsequent call to next.

 4          */

 5         int cursor = 0;

 6 

 7         /**

 8          * Index of element returned by most recent call to next or

 9          * previous.  Reset to -1 if this element is deleted by a call

10          * to remove.

11          */

12         int lastRet = -1;

13 

14         /**

15          * The modCount value that the iterator believes that the backing

16          * List should have.  If this expectation is violated, the iterator

17          * has detected concurrent modification.

18          */

19         int expectedModCount = modCount;

20 

21         public boolean hasNext() {

22             return cursor != size();

23         }

24 

25         public E next() {

26             checkForComodification();

27             try {

28                 int i = cursor;

29                 E next = get(i);

30                 lastRet = i;

31                 cursor = i + 1;

32                 return next;

33             } catch (IndexOutOfBoundsException e) {

34                 checkForComodification();

35                 throw new NoSuchElementException();

36             }

37         }

38 

39         public void remove() {

40             if (lastRet < 0)

41                 throw new IllegalStateException();

42             checkForComodification();

43 

44             try {

45                 AbstractList.this.remove(lastRet);

46                 if (lastRet < cursor)

47                     cursor--;

48                 lastRet = -1;

49                 expectedModCount = modCount;

50             } catch (IndexOutOfBoundsException e) {

51                 throw new ConcurrentModificationException();

52             }

53         }

54 

55         final void checkForComodification() {

56             if (modCount != expectedModCount)

57                 throw new ConcurrentModificationException();

58         }

59     }

lastRetとcursorの2つの変数が表示され、前者はnext()操作で返される要素を表すインデックスであり、後者は次のnext()呼び出しが返されるべき要素のインデックス値であることを示す.remove操作のたびにlastRetが空になり、同時にcursor--は、lastRetに対応する要素がcursorの前にあるため、このときremoveされると、cursorの値は必ず1つ減少します.実はここの反復器実装は基本的にAbstractListのサブクラスによってカバーされており,例えばLinkedList,ArrayListである.前者はランダムアクセスをサポートしていないので、インデックス値を取得要素として使用することはできません.そうしないと、反復器の効率が低下します.
ListIterator(extends Iterator)
Listインタフェースは、Iterableインタフェースを継承するほか、リスト専用の反復器(すなわちListIterator)を取得するためのいくつかの追加の方法(listIterator)があります.LinkedListの反復器実装を参照してください.
private class ListItr implements ListIterator<E> {

        private Node<E> lastReturned = null;

        private Node<E> next;

        private int nextIndex;

        private int expectedModCount = modCount;



        ListItr(int index) {

            // assert isPositionIndex(index);

            next = (index == size) ? null : node(index);

            nextIndex = index;

        }



        public boolean hasNext() {

            return nextIndex < size;

        }



        public E next() {

            checkForComodification();

            if (!hasNext())

                throw new NoSuchElementException();



            lastReturned = next;

            next = next.next;

            nextIndex++;

            return lastReturned.item;

        }



        public boolean hasPrevious() {

            return nextIndex > 0;

        }



        public E previous() {

            checkForComodification();

            if (!hasPrevious())

                throw new NoSuchElementException();



            lastReturned = next = (next == null) ? last : next.prev;

            nextIndex--;

            return lastReturned.item;

        }



        public int nextIndex() {

            return nextIndex;

        }



        public int previousIndex() {

            return nextIndex - 1;

        }



        public void remove() {

            checkForComodification();

            if (lastReturned == null)

                throw new IllegalStateException();



            Node<E> lastNext = lastReturned.next;

            unlink(lastReturned);

            if (next == lastReturned)

                next = lastNext;

            else

                nextIndex--;

            lastReturned = null;

            expectedModCount++;

        }



        public void set(E e) {

            if (lastReturned == null)

                throw new IllegalStateException();

            checkForComodification();

            lastReturned.item = e;

        }



        public void add(E e) {

            checkForComodification();

            lastReturned = null;

            if (next == null)

                linkLast(e);

            else

                linkBefore(e, next);

            nextIndex++;

            expectedModCount++;

        }



        final void checkForComodification() {

            if (modCount != expectedModCount)

                throw new ConcurrentModificationException();

        }

    }

remove操作の考え方はほぼ一致するが,lastRetをチェーンテーブルノードlastReturnedに変換し,removeのたびにnullを置く.取得要素は親バージョンのようにget(i)で直接取得されるわけではありません.反復器は、隣接する2つのノードポインタlastReturnedとnextを保存します.これにより、要素がremove(lastReturned=null)され、nextが再び呼び出されると、nextポインタ値が保存されるため、チェーンテーブル内を移動することができる.
 
IteratorインタフェースListIteratorインタフェースよりもaddメソッドが多く、反復器が指すnext要素の前の位置、すなわち次の要素の前の位置に要素を入れます.
Iterableインタフェース
public interface Iterable<T> {



    /**

     * Returns an iterator over a set of elements of type T.

     *

     * @return an Iterator.

     */

    Iterator<T> iterator();

}

Java Coreで説明したように、Iterableインタフェースを実装すればforeachサイクルで使用できます.のように
class MyCollection implements Iterable<Integer> {



    @Override

    public Iterator<Integer> iterator() {

        return new Iterator<Integer>() {

            public int count = 0;



            @Override

            public boolean hasNext() {



                return count < 10;

            }



            @Override

            public Integer next() {

                return count++;

            }



            @Override

            public void remove() {

                throw new UnsupportedOperationException();

            }



        };

    }



}



public class Fields implements Const {

    public static void main(final String[] args) {



        MyCollection myCollection = new MyCollection();

        for (Integer i : myCollection) {

            System.out.println(i);

        }



    }

}