[Java容器] 迭代器(Iterable+Iterator+ListIterator+Enumeration)详解

[Java容器] 迭代器(Iterable+Iterator+ListIterator+Enumeration)详解_第1张图片

目录

    • 一、Iterable(Java集合框架中顶级接口)
    • 二、Enumeration(远古时期迭代器)
    • 三、Iterator(迭代器)
    • 四、ListIterator(加强版迭代器)
    • 五、Iterator和ListIterator区别


一、Iterable(Java集合框架中顶级接口)

Iterable接口: (java.lang.Iterable) 是Java集合的顶级接口之一。
Collection接口继承Iterable,所以Collection的所有子类也实现了Iterable接口。

public interface Iterable<T> {
    
   // 返回一个迭代器
   Iterator<T> iterator();

   // jdk1.8新加入的方法,遍历
   default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }
   
   // jdk1.8新加入的方法
   default Spliterator<T> spliterator() {
        return Spliterators.spliteratorUnknownSize(iterator(), 0);
    }
}
default:是在java8中引入的关键字,可以在接口中定义方法体。
主要作用:使得接口在进行扩展的时候,不会破坏与接口相关的实现类代码。

测试:

@Test
public void testForEach() {
    List<String> list = Arrays.asList("a","b","c","d","e");
    list.forEach(str -> System.out.println(str);
}

二、Enumeration(远古时期迭代器)

public interface Enumeration<E> {

    // 是否还有元素。
    boolean hasMoreElements();

    // 获取Enumeration
    E nextElement();
}

Enumeration接口早在 JDK1.0 时就推出了,
当时比较早的容器比如 Hashtable, Vector 都使用它作为遍历工具。

public class Hashtable<K,V>
    extends Dictionary<K,V>
    implements Map<K,V>, Cloneable, java.io.Serializable {
	
	// 获取迭代器
	public synchronized Enumeration<V> elements() {
        return this.<V>getEnumeration(VALUES);
    }
    
    private <T> Enumeration<T> getEnumeration(int type) {
        if (count == 0) {
            return Collections.emptyEnumeration();
        } else {
            return new Enumerator<>(type, false);
        }
    }
}

public class Vector<E>
    extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable{

	// 获取迭代器    
	public Enumeration<E> elements() {
        return new Enumeration<E>() {
            int count = 0;

            public boolean hasMoreElements() {
                return count < elementCount;
            }

            public E nextElement() {
                synchronized (Vector.this) {
                    if (count < elementCount) {
                        return elementData(count++);
                    }
                }
                throw new NoSuchElementException("Vector Enumeration");
            }
        };
    }
}

测试:

@Test
public void testIterator() {
     Hashtable<String, String> hash = new Hashtable<>();
     Enumeration<String> hashtableElements = hash.elements();
     while (hashtableElements.hasMoreElements()) {
         System.out.println(hashtableElements.nextElement());
     }

     Vector<String> vector = new Vector<>();
     Enumeration<String> vectorElements = vector.elements();
     while (vectorElements.hasMoreElements()) {
         System.out.println(vectorElements.nextElement());
     }
 }

三、Iterator(迭代器)

迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。

Java中的Iterator功能比较简单,并且只能单向移动:

(1) 使用方法iterator(),要求容器返回一个Iterator。
第一次调用Iterator的next()方法时,它返回序列的第一个元素。
注意:iterator()方法是java.lang.Iterable接口,被Collection继承。

(2) 使用next()获得序列中的下一个元素。

(3) 使用hasNext()检查序列中是否还有元素。

(4) 使用remove()将迭代器新返回的元素删除。

Iterator是Java迭代器最简单的实现,
为List设计的ListIterator具有更多的功能,可以从两个方向遍历List,也可以从List中插入删除元素。

public interface Iterator<E> {

    boolean hasNext();

    E next();

    default void remove() {
        throw new UnsupportedOperationException("remove");
    }

	// 为每个剩余元素执行给定的操作,直到所有的元素都已经被处理或行动将抛出一个异常
    default void forEachRemaining(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        while (hasNext())
            action.accept(next());
    }
}

测试:

@Test
public void testIterator() {
    List<String> list = new ArrayList<>();
    Iterator<String> iterator = list.iterator();
    while (iterator.hasNext()) {
        System.out.println(iterator.next());
    }
}

四、ListIterator(加强版迭代器)

ListIterator

  • 允许我们向前、向后两个方向遍历 List;
  • 允许在遍历时修改 List 的元素;
  • 遍历时获取迭代器当前游标所在位置。

游标( cursor ):在元素之间移动,若集合长度为N,那么游标位置就是N+1。
游标总存在元素中间: ↑ a ↑ b ↑。初始时游标为0,遍历结束时游标为2。

public interface ListIterator<E> extends Iterator<E> {

    boolean hasNext();

    // 返回游标后的值,且游标++。
    E next();

	// 判断游标前面是否有元素;
    boolean hasPrevious();

    // 返回游标前面的元素,同时游标前移一位。
    // 游标前没有元素就报 java.util.NoSuchElementException 的错。
    // 所以使用前最好判断一下。
    E previous();

	// 返回游标后边元素的索引位置,初始为 0;
    int nextIndex();

	// 返回游标前面元素的位置,初始时为-1。
    int previousIndex();

	// 删除迭代器最后一次操作的元素。
	// 当没有迭代,也就是没有调用next()或者previous()直接调用remove时会报java.lang.IllegalStateException错。
    void remove();

	// 更新迭代器最后一次操作的元素为E,也就是更新最后一次调用next()或者previous()返回的元素。
	// 当没有迭代,也就是没有调用next()或者previous()直接调用set时会报java.lang.IllegalStateException错。
    void set(E e);

	// 在游标前面插入一个元素
    void add(E e);
}

ListIterator接口的在ArrayList中具体实现。

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable{

	// 返回指定游标位置的迭代器
    public ListIterator<E> listIterator(int index) {
        if (index < 0 || index > size)
            throw new IndexOutOfBoundsException("Index: "+index);
        return new ListItr(index);
    }
	
	// 返回游标位置为0的迭代器
    public ListIterator<E> listIterator() {
        return new ListItr(0);
    }

	private class Itr implements Iterator<E> {
	
		// 在获取迭代器时指定游标的值,默认为0。
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;

        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];
        }

        // 删除迭代器最后一次操作的元素。lastRet:index of last element returned; -1 if no such
        // 当没有迭代,也就是没有调用next()或者previous()直接调用remove时会报java.lang.IllegalStateException错。
        // 因为lastRet默认为-1,当调用next()后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();
        }
    }

    /**
     * An optimized version of AbstractList.ListItr
     */
    private class ListItr extends Itr implements ListIterator<E> {
        ListItr(int index) {
            super();
            cursor = index;
        }

        public boolean hasPrevious() {
            return cursor != 0;
        }

        public int nextIndex() {
            return cursor;
        }

        public int previousIndex() {
            return cursor - 1;
        }

        @SuppressWarnings("unchecked")
        public E previous() {
            checkForComodification();
            int i = cursor - 1;
            if (i < 0)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            
            // 返回游标前面的元素,且游标--
            cursor = i;
            return (E) elementData[lastRet = i];
        }

        // 设置迭代器最后一次操作的元素。lastRet:index of last element returned; -1 if no such
        // 当没有迭代,也就是没有调用next()或者previous()直接调用set时会报java.lang.IllegalStateException错。
        // 因为lastRet默认为-1,当调用next()后lastRet = i。
        public void set(E e) {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.set(lastRet, e);
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

		// 在游标的前面添加元素
        public void add(E e) {
            checkForComodification();

            try {
                int i = cursor;
                ArrayList.this.add(i, e);
                cursor = i + 1;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
    }
}

五、Iterator和ListIterator区别

(1)ListIterator有add()方法,可以向List中添加对象,Iterator不可以。
(2)ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历。
但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历,Iterator不可以。
(3)ListIterator可以定位当前的索引位置,nextIndex()和previousIndex()可以实现,Iterator不可以。
(4)都可实现删除对象,但是ListIterator可以实现对象的修改,set()方法可以实现。

你可能感兴趣的:(Java集合,Java)