likes
comments
collection
share

记忆深刻的一次BUG,久久不能忘怀

作者站长头像
站长
· 阅读数 14

三目运算符报NPE了!!!??

第一次遇到的时候,年幼无知的我,觉得明明就是很简单的一行代码,怎么会报错,百思不得其解。

模拟问题代码

public class Test {
    private Long money;

    public Long getMoney() {
        return money;
    }

    public void setMoney(Long money) {
        this.money = money;
    }

    public static void main(String[] args) {
        Test test = new Test();
        Long money = Objects.nonNull(test) ? test.getMoney() : 0L;
        System.out.println(money);
    }
}

输出结果

Exception in thread "main" java.lang.NullPointerException
	at com.gree.invoice.b2c.test.Test.main(Test.java:26)

Process finished with exit code 1

## 怎么让代码不报错

两种方法返回结果不一样,根据实际场景选择使用。

方法一:使用Long.valueOf(),输出结果为null。

// 输出结果 null
Long money = Objects.nonNull(test) ? test.getMoney() : Long.valueOf(0L);

方法二:对money字段进行判空,输出结果为0。

// 输出结果 0
Long money = Objects.nonNull(test) && Objects.nonNull(test.getMoney()) ? test.getMoney() : 0L;

原因解析

参考:《新版阿里巴巴Java开发手册》提到的三目运算符的空指针问题到底是个怎么回事?

Long money = Objects.nonNull(test) ? test.getMoney() : 0L;

因为三目运算符的第二,第三位操作数分别为基本数据类型和包装类对象时,根据表达式返回值类型,包装类对象会自动进行拆/装箱操作。

实际运行的代码为:Long money = Long.valueOf(Objects.nonNull(test) ? test.getMoney() : 0L);

因为0L为基本数据类型longLong money要求返回值为包装类型,会触发自动装箱操作,而test.getMoney()为null,Long.valueOf(null)就会导致NPE。

其实,《阿里巴巴Java开发手册(泰山版)》中也有提及: 记忆深刻的一次BUG,久久不能忘怀

编码好习惯

那么平时怎么避免这种问题呢?

那就是保持三目运算符的第二位和第三位表达式的类型一致,最后要做好单元测试。

这也就是为什么改成Long money = Objects.nonNull(test) ? test.getMoney() : Long.valueOf(0L);不会再报错的原因了。

有缘下次再见