zoukankan      html  css  js  c++  java
  • Java暗箱操作之for-each

      对于我们常用的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

  • 相关阅读:
    Vue中v-for不绑定key会怎样
    关于Vuex可直接修改state问题
    不要完全相信Chrome控制台打印的信息
    Vue挂载元素的替换
    (转)openURL的使用方法
    iOS:将NSDate转换为当前时区时间
    OC中使用 static 、 extern、 const使用
    iOS: 正则表达式
    iOS:原生二维码扫描
    iOS:ABPeoplePickerNavigationController系统通讯录使用
  • 原文地址:https://www.cnblogs.com/zhinengfeiyu/p/4772553.html
Copyright © 2011-2022 走看看