概述
组内有同学问了一个问题,对于下面的代码,如果有空指针异常发生,那么可能出现在什么地方
favoriteHouseInfo.setKeyStatus(Null.ofInt(teamHouse::getKeyStatus));
语法分析
MommyTalk-222.png代码执行顺序为
step1: 得到方法引用
teamHouse::getKeyStatus
是一个方法引用,意思是得到一个对象的方法引用
(粗略理解为方法指针),便于在后面的代码里执行
这一步执行完成之后,代码变为了
favoriteHouseInfo.setKeyStatus(Null.ofInt(() -> *ptr method));
由上面的逻辑可知,如果一个对象是null,是没有方法的,所以这里可能会产生空指针异常
step2:工具类执行lambda表达式
Null.ofInt
是一个工具类,代码如下
public static final <T> T ofInt(Supplier<T> expr) {
Supplier<T> defaultValues = () -> (T) new Integer(0);
return of(expr, defaultValues);
}
public static final <T> T of(Supplier<T> expr, Supplier<T> defaultValue) {
try {
T result = expr.get();
if (result == null) {
return defaultValue.get();
}
return result;
} catch (NullPointerException | IndexOutOfBoundsException e) {
return defaultValue.get();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
可以看到会去执行 expr.get()
expr
其实就是 () -> *ptr method)
, 可以理解为无入参代码块
如果有空指针异常,会被捕获
step3: 拆箱
(为什么3在前,4在后,一会儿分析)
对于步骤2的Integer
返回值对象,执行 intValue
方法
可能有空指针
step4: 得到方法签名
步骤3的结果,作为入参,执行 favoriteHouseInfo
对象的 setKeyStatus
方法
方法(除了静态)一定是和对象联系起来的,无对象,无方法
, 所以有可能有空指针异常
结论
方法引用
,背后逻辑是需要获取一个对象的方法引用
, 可能有空指针
自动拆箱
,背后逻辑是默认执行xxValue()
方法,null对象是没有方法的,可能有空指针
方法执行
,null对象是没有方法的,可能有空指针
思考
到底是先拆箱再执行方法,还是先得到方法签名,再拆箱,再执行呢
对于以下代码
public class NullTest {
@Test
public void testProject() {
Hello hello = null;
hello.setInt(
getValue());
}
Integer getValue() {
return null;
}
class Hello {
void setInt(int a) {
}
}
}
编译之后再反编译
javap -verbose NullTest.class
看一下内容
image.png
可以看到在编译期间就已经决定了执行顺序
- 执行
getValue()
- 拆箱,执行
intValue()
- 执行
setInt()
网友评论