Collection接口继承java.lang.Iterable接口,集合类重写了iterator()方法
public interface Iterable<T> { Iterator<T> iterator(); default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); } } default Spliterator<T> spliterator() { return Spliterators.spliteratorUnknownSize(iterator(), 0); } } 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()); } }
原理:
一开始迭代器在所有元素的左边,调用next()之后,迭代器移到第一个和第二个元素之间,next()方法返回迭代器刚刚经过的元素。
hasNext()若返回True,则表明接下来还有元素,迭代器不在尾部。
remove()方法必须和next方法一起使用,功能是去除刚刚next方法返回的元素。
自己实现iterator遍历(参考JDK集合类):
import java.util.Iterator; public class ForEachAPIDemo { public static void main(String[] args) throws Exception { Students students = new Students(10); for (Student student : students) { System.out.println(student.getSid() + ":" + student.getName()); } } } // 支持for each迭代循环的学生集合类 class Students implements Iterable<Student> { // 存储所有学生类的数组 private Student[] students; // 该构造函数可以生成指定大小的学生类变量数组,并初始化该学生类变量数组 public Students(int size) { students = new Student[size]; for (int i = 0; i < size; i++) { students[i] = new Student(String.valueOf(i), "学生" + String.valueOf(i)); } } @Override public Iterator<Student> iterator() { return new StudentIterator(); } // 实现Iterator接口的私有内部类,外界无法直接访问 private class StudentIterator implements Iterator<Student> { // 当前迭代元素的下标 private int index = 0; // 判断是否还有下一个元素,如果迭代到最后一个元素就返回false public boolean hasNext() { return index != students.length; } @Override public Student next() { return students[index++]; } // 这里不支持,抛出不支持操作异常 public void remove() { throw new UnsupportedOperationException(); } } } class Student { private String sid; private String name; public Student(String sid, String name) { setSid(sid); setName(name); } public String getSid() { return sid; } public void setSid(String sid) { this.sid = sid; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Student{" + "sid='" + sid + '\'' + ", name='" + name + '\'' + '}'; } }
foreach原理:
foreach语法最终被编译器转为了对Iterator.next()的调用
package test; import java.util.List; /** * Created by vino on 2016/5/6. */ public class TestForeach { List<Integer> integers; public void testForeach(){ for(Integer i : integers){ } } } // 字节码 public void testForeach(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=3, args_size=1 0: aload_0 1: getfield #2 // Field integers:Ljava/util/List; 4: invokeinterface #3, 1 // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator; 9: astore_1 10: aload_1 11: invokeinterface #4, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z 16: ifeq 32 19: aload_1 20: invokeinterface #5, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object; 25: checkcast #6 // class java/lang/Integer 28: astore_2 29: goto 10 32: return LineNumberTable: line 11: 0 line 13: 29 line 14: 32 LocalVariableTable: Start Length Slot Name Signature 0 2 i Ljava/lang/Integer; 33 0 this Ltest/TestForeach; }
Iterator对Collection 或 Map 进行迭代操作过程中是不允许修改 Collection / Map 的内容(add/remove) 允许set
可以使用 Iterator 本身的方法 remove() 来删除对象
撸代码解释(ArrayList为例):
1.ArrayList的属性modCount:add() remove()时都会modCount++;
2.new Itr(implements Iterator)时属性expectedModCount=modCount,且next()是要检查expectedModCount ?= modCount;
3.调用ArrayList的add() remove()时改变了modCount的值,下一次next()时检查expectedModCount != modCount,throw new ConcurrentModificationException();
4.Iterator 本身的方法 remove()删除元素之后会将modCount重新赋值给expectedModCount。
// ArrayList: public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work return oldValue; } // 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; 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(); } } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }
参考资料:
为什么Iterator的remove方法可保证从源集合中安全地删除对象,而在迭代期间不能直接删除集合内元素