• Java 的三种循环:foreach,Iterator 和 classic for loop


    不得不说,java语言在提供了这三种循环方式带来灵活性的同时,同时也将一些“混乱”引入了进来。

    这里的“混乱”并不是真正意义上的混乱,而是由于没有统一的风格而带来使用习惯的问题——想象一下,如果同一个项目中这三种都有人用,阅读起来真是五味杂陈啊。

    有人要问了,那么,这三种到底哪种好呢?

    在回答这个问题之前,能告诉我“好”的定义是什么吗?

    我所认为的好,无非2点——1、代码简洁;2、性能高效

    接下来,我们对这3种for循环方式一一评估。

    Classic for loop

    首先,来看看classic for loop.

    [java] view plaincopy
     
     
    1. <pre name="code" class="java">List<String> birds = new ArrayList<String>() {  
    2.     {  
    3.         add("magpie");  
    4.         add("crow");  
    5.         add("emu");  
    6.     }  
    7. };  
    8. for (int i = 0; i < birds.size(); i++) {  
    9.     String bird = birds.get(i);  
    10. }  
    
    


    这种方式,代码风格还好,可惜的是,有个隐藏的性能问题。

    对于List接口的众多实现类来讲,并不是每个实现的get(i)都是O(1)时间的。比如LinkedList的时间复杂度就是O(n)。

    这样,每次调用get方法的性能从固定时间变为了随着n增长而增长的线性时间。

    (这里,我不打算讨论list.size()方法的性能,如果仅仅从LinkedList和ArrayList这样常用的方法来看,它的性能损失可以忽略不计,除非是追求极致)

    (图片引用自:ArrayList vs. LinkedList vs. Vector [1])

    换句话讲,如果上面的List实现换成LinkedList,这样的代码就可能存在隐藏的性能问题。(当List比较大且频繁调用的情况下)

    而恰恰Java又是提倡隐藏实现细节的语言,使用者往往并不知道传入的List实现究竟是哪一种。所以……可能,仅仅是可能,一个隐藏的性能地雷埋下了。

    Iterator 

    现在,来看看 iterator for 循环。

    上面那个例子,稍加改动就成为了下面这样:

    [java] view plaincopy
     
     
    1. List<String> birds = new ArrayList<String>() {  
    2.     {  
    3.         add("magpie");  
    4.         add("crow");  
    5.         add("emu");  
    6.     }  
    7. };  
    8. for (Iterator<String> itr = birds.iterator(); itr.hasNext();) {  
    9.     String bird = itr.next();  
    10. }  


    从性能角度来看,这种方式还好,获取每个元素都是固定时间,但是,从代码风格来看,略显复杂了。

    不过,iterator有个优点,就是可以在循环体内删除列表中的元素可能成功-依赖List的具体实现),而其他的2种方式不行。

    [java] view plaincopy
     
     
    1. List<String> birds = new ArrayList<String>() {  
    2.     {  
    3.         add("magpie");  
    4.         add("crow");  
    5.         add("emu");  
    6.     }  
    7. };  
    8. // 下面的for循环执行后,birds列表将被清空  
    9. for (Iterator<String> itr = birds.iterator(); itr.hasNext();) {  
    10.     String bird = itr.next();  
    11.     itr.remove();  
    12. }  


    而下面这种方式是错误的

    [java] view plaincopy
     
     
    1. List<String> birds = new ArrayList<String>() {  
    2.     {  
    3.         add("magpie");  
    4.         add("crow");  
    5.         add("emu");  
    6.     }  
    7. };  
    8. // 下面的for循环执行时将会抛出异常  
    9. for (String bird : birds) {  
    10.     birds.remove(bird);  
    11. }  

    Foreach

    最后,来看看用JDK5引入的神器,foreach循环。

    [java] view plaincopy
     
     
    1. List<String> birds = new ArrayList<String>() {  
    2.     {  
    3.         add("magpie");  
    4.         add("crow");  
    5.         add("emu");  
    6.     }  
    7. };  
    8. for (String bird : birds) {  
    9. }  

    从代码风格上来看,它最简洁。那么性能如何呢?

    其实,对于集合来说,它只是Iterator循环的包装(甜头),编写代码的时候简化了代码,而编译的时候依然是用Iterator实现的。

    对于数组类型,还是用的classic for loop实现。

    所以,性能也是最优的。

    对比一下这三种方式,我们可以得出结论:

      简洁性 性能
    classic for loop OK 可能会差
    Iterator
    foreach

    所以,如果可以,尽量选择使用foreach循环,简洁且高效。

    引用:

    [1] ArrayList vs. LinkedList vs. Vector http://www.programcreek.com/2013/03/arraylist-vs-linkedlist-vs-vector/

  • 相关阅读:
    springboot自动装配原理
    @Inherited 注解的作用
    基础知识点:链表反转
    基础知识点:二叉树的层次遍历
    算法题:8、二进制中1的个数
    微服务_GPRC
    扎实基础_数据结构
    .net core3.0程序发布到linux+docker
    c#_安全漏洞总结
    IIS Express(电脑无管理员权限如何启用VS调试)
  • 原文地址:https://www.cnblogs.com/hxj914103719/p/4372004.html
Copyright © 2020-2023  润新知