今天写代码的时候,需要遍历一个作为参数传递进来的容器,
当时顺手就加上了判空条件:
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更安全(不会带来数组越界的错误),但是最终编译结果和以前的写法是一样的。