你可能不清楚的Java细节(2)--for及for-each各自循环适用的场景

来源:互联网 发布:sql server创建视图 编辑:程序博客网 时间:2024/05/15 14:19

本文参考资料基于JDK1.8,理论上也适用于之前的版本.

严格的说,for-each是对for的增强,本质上也属于for循环.

for和for-each一般无非也就是如下三种用法,其中第三种也就是我们平时所说的for-each:

//其中list为java.util.List类型//第一种写法for (int i=0, n=list.size(); i < n; i++){    list.get(i);}//第二种写法for (Iterator i=list.iterator(); i.hasNext(); ){    i.next();}//第三种写法:增强型for循环,即for-each    for(T obj : list){    //TODO}

经常在写for循环的时候会很困惑:到底用哪种写法最合适.

一步步来看.

在JLS第14.14.2章节 The enhanced for statement中对for-each的有说明,原文太长有兴趣可以点进去自行去看,大体上就是说:

  1. 能使用for-each进行循环的对象,要么是直接或间接的实现了Iterable接口,要么就是个数组.
  2. 如果是数组,那么在执行的时候JVM会解释成如下形式,即第一种写法:
    for (int i=0, n=list.size(); i < n; i++){
    list.get(i);
    }
    //特别要注意,是解释成上面这种写法,而不是下面这样的.毕竟前者的在性能上会更好一些.
    for (int i=0; i < list.size(); i++){
    list.get(i);
    }

3.如果是实现了Iterable接口,那么在执行的时候JVM会解释成如下形式,即第二种写法:

    for (Iterator i=list.iterator(); i.hasNext(); ){        i.next();    }

而JDK中Iterable接口的API也指明了该接口是为了让实现类成为for-each语句的目标.

鉴于在执行时JVM会根据对象是数组还是Iterable接口的实现类来自行决定解释成具体哪种形式的写法,因此,虽然for-each有它的局限性,但大部分情况下,我们都可以用for-each替代for,毕竟for-each可以让代码显得更简洁逻辑也更清晰.

但是,还是有例外的情况,那就是既实现了Iterable又实现了RandomAccess的类,比如最常见的ArrayList.

RandomAccess的API中有指明,实现了RandomAccess接口的类(准确的说,是属于随机访问的List,因为属于随机访问的List应当实现RandomAccess接口),在进行循环时,更适合采用第一种写法(自然也就不适合使用for-each,因为for-each只会判断是不是数组、是不是实现了Iterable接口,并没有对是否实现RandomAccess进行判断).

所以,整个的结论就是:

  1. 如果是数组,则采用第一种或第三种.
  2. 如果是实现了Iterable接口,并且未实现RandomAccess接口(不是随机访问的List),则应当使用第二种或第三种,优先使用第三种即for-each.
  3. 如果是实现了Iterable接口,并且实现了RandomAccess接口(是随机访问的List),则应当使用第一种.

参考资料:

  1. JLS第14.14.2章节 The enhanced for statement
  2. JDK1.8 API
0 0
原创粉丝点击