Java foreach语法糖探秘

原创 2016年06月01日 14:36:58

    前不久线上用foreach循环,由于没判空,导致线上报了很多空指针异常。这两天梳理下foreach语法糖,看看jvm底层到底如何实现的。

    先写一个foreach的demo,包含对list对象和数组对象的遍历。

package com.jd.lvsheng;

import java.util.ArrayList;
import java.util.List;

public class Main {

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

		String[] arr = new String[3];
		for (String s : arr) {
			System.out.println(s);
		}
	}
}

    然后对生成的class文件执行javap命令:javap -c Main,于是可以看这个文件的字节码了。

Compiled from "Main.java"
public class com.jd.lvsheng.Main extends java.lang.Object{
public com.jd.lvsheng.Main();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   new     #2; //class java/util/ArrayList
   3:   dup
   4:   invokespecial   #3; //Method java/util/ArrayList."<init>":()V
   7:   astore_1
   8:   aload_1
   9:   invokeinterface #4,  1; //InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
   14:  astore_2
   15:  aload_2
   16:  invokeinterface #5,  1; //InterfaceMethod java/util/Iterator.hasNext:()Z
   21:  ifeq    44
   24:  aload_2
   25:  invokeinterface #6,  1; //InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
   30:  checkcast       #7; //class java/lang/String
   33:  astore_3
   34:  getstatic       #8; //Field java/lang/System.out:Ljava/io/PrintStream;
   37:  aload_3
   38:  invokevirtual   #9; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   41:  goto    15
   44:  iconst_3
   45:  anewarray       #7; //class java/lang/String
   48:  astore_2
   49:  aload_2
   50:  astore_3
   51:  aload_3
   52:  arraylength
   53:  istore  4
   55:  iconst_0
   56:  istore  5
   58:  iload   5
   60:  iload   4
   62:  if_icmpge       85
   65:  aload_3
   66:  iload   5
   68:  aaload
   69:  astore  6
   71:  getstatic       #8; //Field java/lang/System.out:Ljava/io/PrintStream;
   74:  aload   6
   76:  invokevirtual   #9; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   79:  iinc    5, 1
   82:  goto    58
   85:  return

}

    从第9,16,25行可以看出来,foreach在遍历List对象的时候,实则试用iterator迭代器来进行循环遍历的。循环的过程体现在21,41行。21行的ifeg命令会拿栈顶值和0比较,如果相等,则跳到44行,结束这个for循环。如果不等,会顺序执行到44行,goto 15, 也就是跳回15行。这个很像汇编语言for循环的实现。这段代码的实际等效java代码如下:

		Iterator<String> iter = list.iterator();
		while (iter.hasNext()) {
			System.out.println(iter.next());
		}


    再来看数组,数组的实现机制跟List完全不一样!因为数组并没有实现Iterator接口。

    数组是先获取数组对象的长度,然后根据这个长度来遍历的。52行的指令是arraylength,用于获得数组的长度值并压入栈顶。而62和82行构成了一个循环。if_icmpge会比较栈顶两int型数值大小,当结果大于等于0时跳转到85行。79行iinc会将第5个变量自增1.这不就是一个for循环吗!这段字节码的实际等效java代码如下:

		int len = arr.length;
		for (int i = 0; i < len; i++) {
			System.out.println(arr[i]);
		}

    分析到这里,心里就清楚了,要用foreach循环,必须保证要遍历的对象非空。语法题虽然很甜,使用方便,但是不能觉解其底层实现,用起来心惊胆战的。。。

    只有知其然且知其所以然,才能写出鲁棒性(Robustness)更好的代码。


版权声明:本文为博主原创文章,未经博主允许不得转载。

Java语法糖之foreach

语法糖是一种几乎每种语言或多或少都提供过的一些方便程序员开发代码的语法,它只是编译器实现的一些小把戏罢了,编译期间以特定的字节码或者特定的方式对这些语法做一些处理,开发者就可以直接方便地使用了。这些语...
  • u013256816
  • u013256816
  • 2016年02月25日 11:39
  • 3914

java中for和foreach的区别

普通for循环 for(int i=0;i
  • u010031673
  • u010031673
  • 2016年07月01日 12:41
  • 10629

Java8 Foreach操作

在这篇文章中我将向你演示如何使用Java8中的foreach操作List和Map 1. Foreach操作Map 1.1 正常方式遍历Map MapString, Integer> it...
  • waterdemo
  • waterdemo
  • 2017年09月18日 17:02
  • 912

java8 forEach Map List

java8 forEach 在Map和List中的使用 原始的使用Map items = new HashMap(); items.put("A", 10); items.put("B", 20); ...
  • wtljiayou
  • wtljiayou
  • 2016年12月14日 13:53
  • 14317

JAVA foreach和普通for循环是否需要判断为null

public static void main(String[] args) { List list = null; for(Object s : list){ System.out.p...
  • rnZuoZuo
  • rnZuoZuo
  • 2014年05月06日 13:12
  • 19417

foreach 空指针(jdk1.7)

最近碰到了个问题,发现foreach里面并没有为我们判断引用对象是否为空。所以测试了一下。 以下为测试代码: package test; import java.util.List; pu...
  • wuyuanwei123
  • wuyuanwei123
  • 2017年04月01日 09:36
  • 426

谈谈Java中的语法糖

语法糖(Syntactic Sugar),也称糖衣语法,指在计算机语言中添加的某种语法,这种语法对语言本身功能来说没有什么影响,只是为了方便程序员的开发,提高开发效率。说白了,语法糖就是对现有语法的一...
  • danchu
  • danchu
  • 2017年02月11日 20:43
  • 5953

java语法糖

一、定义        什么叫语法糖?顾名思义,我的理解是,编程语言给程序员提供的一些个便利的操作,在保证性能的基础上提高开发效率。 帖一下百度百科解释: 语法糖(Syntactic su...
  • liuyongvs2009
  • liuyongvs2009
  • 2014年11月22日 09:59
  • 1376

Java 中的语法糖 (Syntactic Sugar)

语法糖(Syntactic Sugar),也叫糖衣语法,是英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语。指的是,在计算机语言中添加某种语法,这种语法能使程序员更方便...
  • ol_beta
  • ol_beta
  • 2011年09月18日 15:12
  • 16906

关于Foreach是如何实现的问题

在探讨foreach如何内部如何实现这个问题之前,我们需要理解两个C#里边的接口,IEnumerable 与 IEnumerator. 在C#里边的遍历集合时用到的相关类中,IEnumerable是...
  • sundacheng1989
  • sundacheng1989
  • 2015年10月28日 12:57
  • 1830
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Java foreach语法糖探秘
举报原因:
原因补充:

(最多只允许输入30个字)