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

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

if(null==list)return;

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

下面看实验结果:

public static voidmain(String[] args) {

List 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

3 }

遍历容器:

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

}

jdk1.5之后:

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

}

代码看起来优雅了许多。

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

下面看测试代码:

List list = new ArrayList<>();

String[] test= newString[]{};//遍历容器测试

public voidcollectionForeachTest() {for(String s : list) {//do something

}

}//循环容器测试

public voidcollectionIteatorTest() {

Iterator iterator =list.iterator();while(iterator.hasNext()) {//do something

}

}//遍历数组测试

public voidarrayForeachTest() {for(String s : test) {//do something

}

}//循环数组测试

public voidindexTest() {for (int i = 0; i < test.length; i++) {//do something

}

}

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

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

public voidcollectionForeachTest();

Code:0: aload_01: getfield #4 //Field list:Ljava/util/List;

4: invokeinterface #7, 1 //InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;

9: astore_110: aload_111: invokeinterface #8, 1 //InterfaceMethod java/util/Iterator.hasNext:()Z

16: ifeq 32

19: aload_120: invokeinterface #9, 1 //InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;

25: checkcast #5 //class java/lang/String

28: astore_229: goto 10

32: return

public voidcollectionIteatorTest();

Code:0: aload_01: getfield #4 //Field list:Ljava/util/List;

4: invokeinterface #7, 1 //InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;

9: astore_110: aload_111: invokeinterface #8, 1 //InterfaceMethod java/util/Iterator.hasNext:()Z

16: ifeq 22

19: goto 10

22: return

数组:遍历和索引:

public voidarrayForeachTest();

Code:0: aload_01: getfield #6 //Field test:[Ljava/lang/String;

4: astore_15: aload_16: arraylength7: istore_28: iconst_09: istore_310: iload_311: iload_212: if_icmpge 26

15: aload_116: iload_317: aaload18: astore 4

20: iinc 3, 1

23: goto 10

26: return

public voidindexTest();

Code:0: iconst_01: istore_12: iload_13: aload_04: getfield #6 //Field test:[Ljava/lang/String;

7: arraylength8: if_icmpge 17

11: iinc 1, 1

14: goto 2

17: return

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

结论:

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

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

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐