Java开发如何预防空指针异常

一、什么是空指针异常

空指针异常(NullPointerException)是一种在Java等编程语言中常见的异常类型,它发生在尝试调用一个空(null)对象的属性或方法时。

空指针异常通常发生在以下两种情况:

  • 有一个对象没有分配空间,即它是一个空对象,这可能是因为一个对象类型的属性没有直接初始化,或者在定义了一个对象类型的变量后,赋值为null。
  • 尝试直接调用该空对象的属性或方法,例如,尝试访问一个null值的字符串的charAt方法,或者调用一个null值的List的add方法。

在Java中,空指针异常通常会导致程序崩溃,因此通常需要避免这种情况的发生。

二、如何避免空指针异常

下面是举一个例子,假设userList是存在空对象的

public static List<User> getOldMan() {
        List<Long> ids = Collections.singletonList(1000L);
        List<User> userList = getUser(ids);
        List<User> resultList = new ArrayList<>(10);
        for (User user : userList) {
            if (null != user){//直接加判空
                Long id = user.getId();
                String name = user.getName();
                int age = user.getAge();
                SexyEnum sexy = user.getSex();
                //找出性别是男性的,40岁以上的人员
                if (age > 40 && sexy.getValue().equals(SexyEnum.MAN.getSexy())) {
                    resultList.add(user);
                }
            }
        }
        return resultList;
}

1.最直接的方式,if判断

常规的做法是直接判空

        for (User user : userList) {
            if (null != user){//直接加判空
                Long id = user.getId();
                String name = user.getName();
                int age = user.getAge();
                SexyEnum sexy = user.getSex();
                //找出性别是男性的,40岁以上的人员
                if (age > 40 && sexy.getValue().equals(SexyEnum.MAN.getSexy())) {
                    resultList.add(user);
                }
            }
        }

或者continue,减少一些代码层级结构

        for (User user : userList) {
            if (null == user) {//使用continue减少代码层级结构
                continue;
            }
            Long id = user.getId();
            String name = user.getName();
            int age = user.getAge();
            SexyEnum sexy = user.getSex();
            //找出性别是男性的,40岁以上的人员
            if (age > 40 && sexy.getValue().equals(SexyEnum.MAN.getSexy())) {
                resultList.add(user);
            }
        }

2.其他更优雅的判空方式

假如userList也可能为空,那么代码将变得很臃肿

    public static List<User> getOldMan() {
        //假如userList也可能是空,那么我们的程序就显得很臃肿
        List<Long> ids = Collections.singletonList(1000L);
        List<User> userList = getUser(ids);
        if(null == userList){
            return Collections.emptyList();
        }
        List<User> resultList = new ArrayList<>(10);
        for (User user : userList) {
            if (null == user) {//使用continue减少代码层级结构
                continue;
            }
            Long id = user.getId();
            String name = user.getName();
            int age = user.getAge();
            SexyEnum sexy = user.getSex();
            //找出性别是男性的,40岁以上的人员
            if (age > 40 && sexy.getValue().equals(SexyEnum.MAN.getSexy())) {
                resultList.add(user);
            }
        }
        return resultList;
    }

这里建议使用JDK8的Optional、stream流,代码会更加简洁优雅

    public static List<User> getOldMan() {
        List<Long> ids = Collections.singletonList(1000L);
        List<User> userList = getUser(ids);
        return Optional.ofNullable(userList).orElseGet(Collections::emptyList).stream().filter(Objects::nonNull)
                .filter(user -> user.getAge() > 40 && user.getSex().getValue().equals(SexyEnum.MAN.getSexy())).collect(Collectors.toList());
    }

关于JDK8的其他用法,我在另一篇博客有介绍,感兴趣的可以去看

Java8新特性-CSDN博客

3.接口的入参都做考虑加判空

对于提供给外部的接口,亦或者是本类的私有方法,只要是入参,养成一个习惯。

第一时间检查入参是否有可能是空的,并做容错处理,或直接返回,给出提示或记录日志。

4.利用IDEA的sonar扫描工具

IDEA plugins安装sonarLint扫描工具,可以扫描出当前类明显的空指针问题

5.初始化对象尽量不赋予空值

比如方法返回集合时,使用Collections.emptyList()返回空集合,那么在调用方使用的时候可以避免很多无意义的空判断和使用问题

public static List<User> getOldMan() {
        List<Long> ids = Collections.singletonList(1000L);
        List<User> userList = getUser(ids);
        if(null == userList){
            //返回空集合
            return Collections.emptyList();
        }

        //....

6.写接口单元测试

有时候在一些业务场景中,参数值一般都是有的,只有在一些特定的业务场景才会暴露出问题。如果我们有意的传入空值或者一些边界值,测试方法,很多问题往往能在开发阶段提早发现。

 

=========================================================================创作不易,请勿直接盗用,使用请标明转载出处。

喜欢的话,一键三连,您的支持是我一直坚持高质量创作的原动力。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值