Java ForEach 语句判断是否为空

用户头像
引花眠
关注
发布于: 2020 年 08 月 23 日

一段犯错的代码

在程序中,有一段获取历史数据并循环处理的逻辑,有一天忽然报空指针异常,大致逻辑如下:

List<String> buttons = getButtons();
for (String button: buttons ) {
}

提示是在第二行报错,分析原因可能getButtons()返回null,

然后我写了一段测试代码:

@Test
public void testForEachNull() {
List<String> buttons = null;
for (String button : buttons) {
System.out.println(button);
}
}

异常如下:

java.lang.NullPointerException
at com.github.laozhaishaozuo.basic.ForTest.testForEachNull(ForTest.java:39)
....


分析原因

之前一直以为forEach方法可以循环null数据,但是这次的bug让我明白原来不行,那么到底是为什么呢,于是我用ByteCode Outline工具查看了一下字节码:

// access flags 0x1
public testForEachNull()V
@Lorg/junit/Test;()
L0
LINENUMBER 38 L0
ACONST_NULL
ASTORE 1
L1
LINENUMBER 39 L1
ALOAD 1
INVOKEINTERFACE java/util/List.iterator()Ljava/util/Iterator; //重点在这里
ASTORE 3
GOTO L2
L3
FRAME FULL [com/github/laozhaishaozuo/basic/ForTest java/util/List T java/util/Iterator] []
ALOAD 3
INVOKEINTERFACE java/util/Iterator.next()Ljava/lang/Object;
CHECKCAST java/lang/String
ASTORE 2
L4
LINENUMBER 40 L4
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 2
INVOKEVIRTUAL java/io/PrintStream.println(Ljava/lang/String;)V
L2
LINENUMBER 39 L2
FRAME SAME
ALOAD 3
INVOKEINTERFACE java/util/Iterator.hasNext()Z
IFNE L3
L5
LINENUMBER 42 L5
RETURN
L6
LOCALVARIABLE this Lcom/github/laozhaishaozuo/basic/ForTest; L0 L6 0
LOCALVARIABLE buttons Ljava/util/List; L1 L6 1
// signature Ljava/util/List<Ljava/lang/String;>;
// declaration: java.util.List<java.lang.String>
LOCALVARIABLE button Ljava/lang/String; L4 L2 2
MAXSTACK = 2
MAXLOCALS = 4


以上字节码的大致逻辑是

  1. 创建一本地变量1然后赋值

  2. 调用变量1上的iterator()方法返回一个Iterator对象,存储在变量3

  3. 继续调用Iterator对象的hasNext()next()方法返回List中的对象,存储在变量2

  4. 对返回的对象进行操作…

由以上字节码可以看出,Java对forEach的支持是通过将其转换为Iterator来实现的,所以对于null引用会直接报空指针异常。



发布于: 2020 年 08 月 23 日 阅读数: 45
用户头像

引花眠

关注

还未添加个人签名 2018.06.11 加入

还未添加个人简介

评论

发布
暂无评论
Java ForEach语句判断是否为空