你的位置:首页 > Java教程

[Java教程]Java暗箱操作之for


  对于我们常用的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();    }  }  }

 

输出结果:

12345678910-------------------------------------------索引: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