使用foreach需要判空。

今天写代码的时候,需要遍历一个作为参数传递进来的容器,

当时顺手就加上了判空条件:

if(null==list)return;

后来就像,不知道遍历(foreach)有没有帮我做这个工作:

下面看实验结果:

public static void main(String[] args) {
        List<String> list =null;
        for (String s:list){
            System.out.println(s);
        }
    }

运行时报空指针错误:

Exception in thread "main" java.lang.NullPointerException
    at Test.main(Test.java:37)

说明在进行foreach遍历的时候,需要判空的。

下面看看foreach到底是怎么实现的:

foreach是在jdk 1.5版本后推出更优雅的遍历写法:

jdk1.5之前:

遍历数组:

1  for (int i=0;i<array.length;i++){
2    //do something
3 }

遍历容器:

while (list.iterator().hasNext()){
            //do something
        }

jdk1.5之后:

 for (String s:list){
           //do something
        }

代码看起来优雅了许多。

那foreach是一个新的东西么?相对于以前的的for循环来说,到底哪个效率要高一些呢?

下面看测试代码:

    List<String> list = new ArrayList<>();
    String[] test = new String[]{};

    //遍历容器测试
    public void collectionForeachTest() {
        for (String s : list) {
            //do something
        }
    }

    //循环容器测试
    public void collectionIteatorTest() {
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            //do something
        }
    }

    //遍历数组测试
    public void arrayForeachTest() {
        for (String s : test) {
            //do something  
        }
    }

    //循环数组测试
    public void indexTest() {
        for (int i = 0; i < test.length; i++) {
            //do something
        }
    }

首先编译。javap -c Test.class查看编译源文件:

容器:使用遍历和迭代器:

public void collectionForeachTest();
    Code:
       0: aload_0
       1: getfield      #4                  // Field list:Ljava/util/List;
       4: invokeinterface #7,  1            // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
       9: astore_1
      10: aload_1
      11: invokeinterface #8,  1            // InterfaceMethod java/util/Iterator.hasNext:()Z
      16: ifeq          32
      19: aload_1
      20: invokeinterface #9,  1            // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      25: checkcast     #5                  // class java/lang/String
      28: astore_2
      29: goto          10
      32: return

  public void collectionIteatorTest();
    Code:
       0: aload_0
       1: getfield      #4                  // Field list:Ljava/util/List;
       4: invokeinterface #7,  1            // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
       9: astore_1
      10: aload_1
      11: invokeinterface #8,  1            // InterfaceMethod java/util/Iterator.hasNext:()Z
      16: ifeq          22
      19: goto          10
      22: return

数组:遍历和索引:

 public void arrayForeachTest();
    Code:
       0: aload_0
       1: getfield      #6                  // Field test:[Ljava/lang/String;
       4: astore_1
       5: aload_1
       6: arraylength
       7: istore_2
       8: iconst_0
       9: istore_3
      10: iload_3
      11: iload_2
      12: if_icmpge     26
      15: aload_1
      16: iload_3
      17: aaload
      18: astore        4
      20: iinc          3, 1
      23: goto          10
      26: return

  public void indexTest();
    Code:
       0: iconst_0
       1: istore_1
       2: iload_1
       3: aload_0
       4: getfield      #6                  // Field test:[Ljava/lang/String;
       7: arraylength
       8: if_icmpge     17
      11: iinc          1, 1
      14: goto          2
      17: return

 

可以看出来,总体来说:foreach就是iterator的语法糖,使用foreach,最后都会编译成传统的Iterator的方法。

结论:

1.使用foreach需要检查对象是否为空,因为使用foreach相当于使用了obj.itreator()

2.foreach只是一个语法糖,使用foreach更安全(不会带来数组越界的错误),但是最终编译结果和以前的写法是一样的。

 

posted @ 2018-04-14 17:24  胖毛  阅读(12227)  评论(0编辑  收藏  举报