考虑以下代码:
int[] r = null;
r[0] = 1 % 0;
我本以为这会引发NullPointerException
: 根据JLS 第 15.7.1 节 https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.7.1:
二元运算符的左侧操作数似乎在右侧操作数的任何部分被求值之前被完全求值。
=
是一个二元运算符(如JLS 第 15.2 节 https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.2- JLS Sec 15.26 描述了赋值运算符),并且完全评估左侧操作数将导致NullPointerException
。然而,一个ArithmeticException
抛出,表示在完全评估左侧操作数之前评估右侧操作数。
Why?
规格简单的赋值运算符 https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.26.1描述了这种行为:
...
如果左侧操作数是数组访问表达式(第 15.10.3 节),可能用一对或多对括号括起来,则:
- 首先,计算左侧操作数数组访问表达式的数组引用子表达式。如果此计算突然完成,则出于同样的原因,赋值表达式也会突然完成;索引子表达式(左侧操作数数组访问表达式的)和右侧操作数不会被求值,也不会发生赋值。
这样就正常完成了。
- 否则,将计算左侧操作数数组访问表达式的索引子表达式。如果此计算突然完成,则赋值表达式也会出于同样的原因突然完成,并且不会计算右侧操作数并且不会发生赋值。
这样就正常完成了。
- 否则,将计算右侧操作数。如果此计算突然完成,则赋值表达式也会出于同样的原因突然完成,并且不会发生赋值。
这突然完成,与ArithmeticException
.
- 否则,如果数组引用子表达式的值为 null,则不会发生赋值并引发 NullPointerException。
这永远不会被执行。
因此,第 15.7.1 节的引用似乎存在不一致之处,或者至少过于简单化。
有趣的是,对于复合赋值运算符,没有观察到相同的行为,例如
int[] arr = null;
arr[0] += 1 % 0;
does产量aNullPointerException
.
JLS 第 15.26.2 节 https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.26.2描述了这一点。不过,这也许并不令人惊讶,因为:
形式的复合赋值表达式E1 op= E2
相当于E1 = (T) ((E1) op (E2))
, where T
是类型E1
, 除了那个E1
仅评估一次。
换句话说,这段代码(大致)相当于:
arr[0] = arr[0] + 1 % 0;
so the NullPointerException
发生在评估右手简单赋值的操作数。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)