对于我们常用的ArrayList等容器类,经常需要一个一个遍历里面的元素,从而对各个元素执行对应的操作。

  像我代码写多了,通常的做法是用传统的,类似于数组遍历的方法,即在for循环中设置一个int变量作为索引,然后用List的get方法,想怎么做就怎么做,不会遇到任何不能做的事。

  当然,偶尔我会写得简单一点,用 for (元素类型 变量名 :集合) 的方法,即不用索引,直接指定实际的元素类型,取下一个元素,这样可以少写一行代码。

  但不管用哪一种,我都没有考虑过用迭代器iterator,虽然教程上面经常提到这东西,我也知道这是用来遍历,顺便执行删除等操作的。因为用类似数组遍历的方法取元素从未遇到过瓶颈,就从来没研究过iterator,也一直都觉得这是个没有卵用的东西。

  最近在研究ArrayList和LinkedList源码的时候,源码里面也有很大一段是关于Iterator的,这让我更加不解了:既然是一个可有可无可替代的东西,为什么官方还要费这么大的劲来描述它呢?

 

  直到最近阅读《Effective Java》,看了一节关于for-each和传统for循环的比较,里面有一句话让我重新审视Iterator:

    Not only does the for-each loop let you iterate over collections and arrays,

    it lets you iterate over any object that implements the Iterable interface.

    这就不得不让我怀疑:难道我以前所知道的集合类,就是因为实现了Iterable接口,才可以用for加冒号的方式?

  

  google了一下,果然,for-each这样一种简洁的书写方式,内部居然就是用迭代器实现的!

  下面的代码摘自StackOverFlow  

  

List<String> someList = new ArrayList<String>();

 

   正常的用for-each遍历方法:

 

for (String item : someList) {
    System.out.println(item);
}

  重点来了,上面这简单的一句话,在编译过程中,被编译器自动翻译成了下面这段,真正执行的时候也正是下面这段:

for(Iterator<String> i = someList.iterator(); i.hasNext(); ) {
    String item = i.next();
    System.out.println(item);
}

 

   

  所以,在实际开发中,虽然明面上很少用到标标准准的Iterator,但是常用的for-each的暗箱操作却都是Iterator!

  Java创造出来for-each的操作,好处之一当然是简化了代码的书写,减少了变量个数。

  另外还有很重要的一点是大大降低了遍历过程当中的误操作。想想看,如果在for-each过程中,你得到了当前位置的元素值,有什么办法可以添加、删除或修改元素值呢?答案是没有。然而利用Iterator或者索引来写循环,你可以进行几乎所有的增删改操作。所以利用for-each来操作更安全。

 

  当然,for-each还有一种用法,即用在普通数组的遍历当中,当中也进行了暗箱操作,即转换为索引的遍历。

int[] test = new int[] {1,4,5,7};

for (int intValue : test) {
    // do some work here on intValue
}

  

  编译时转换为:

 

int[] test = new int[] {1,4,5,7};

for (int i = 0; i < test.length; i++) {
    int intValue = test[i];
    // do some work here on intValue
}

 

 

 一定要注意,for-each只能用于:①Iterable ②数组

也即,除了数组以外,一般的类只要实现了Iterable接口就能用for-each

 

我们可以随便写个类玩玩。

import java.util.Iterator;


public class MyClass<E> implements Iterable<E>{
    
    private class MyIterator implements Iterator<E> {
        
        private int max = 10;
        private int cur = 0;

        @Override
        public boolean hasNext() {
            if (cur < max)
                return true;
            else
                return false;
        }

        @SuppressWarnings("unchecked")
        @Override
        public E next() {
            Object res = ++cur;
            return (E) res;
        }

        @Override
        public void remove() {
            System.out.println("索引:"+cur+" 被删除");
        }
        
    };

    @Override
    public Iterator<E> iterator() {
        return new MyIterator();
    }
    
}

 

测试下

import java.util.Iterator;


public class JavaMain {

    public static void main(String[] args) {
        MyClass<Integer> m = new MyClass<>();
        for (Integer i : m) {
            System.out.println(i);
        }
        System.out.println("-------------------------------------------");
        for (Iterator<Integer> it = m.iterator();it.hasNext();) {
            Integer val = it.next();
            if (val % 3 == 0)
                it.remove();
        }
    }
    

}

 

输出结果:

1
2
3
4
5
6
7
8
9
10
-------------------------------------------
索引:3 被删除
索引:6 被删除
索引:9 被删除

 

 

 我们这里的MyClass类没有任何实际的意义,居然试验成功了,真是一件不可思议的事情。。。

 

参考资料:

http://stackoverflow.com/questions/85190/how-does-the-java-for-each-loop-work

http://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.14.2

 

posted on 2015-08-31 13:06  智能飞鱼  阅读(389)  评论(0编辑  收藏  举报