• 如何优雅的避免空指针异常


    空指针异常是导致java程序运行中断最常见的原因,相信每个程序猿都碰见过,也就是NullPointException,我们通常简称为NPE,本文告诉大家如何优雅避免NPE。

    1.数据准备

    package npe;
    
    /**
     * @author 百里
     */
    public class User {
        private String name;
        private int age;
        private Address address;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public Address getAddress() {
            return address;
        }
    
        public void setAddress(Address address) {
            this.address = address;
        }
    
        public User(){
    
        }
    
        public User(String name, int age, Address address) {
            this.name = name;
            this.age = age;
            this.address = address;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", address=" + address +
                    '}';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    package npe;
    
    /**
     * @author 百里
     */
    public class Address {
        private String street;
        private String city;
        private String country;
    
        public Address(){
    
        }
        
        public Address(String street, String city, String country) {
            this.street = street;
            this.city = city;
            this.country = country;
        }
    
        // getters and setters
        public String getStreet() {
            return street;
        }
    
        public void setStreet(String street) {
            this.street = street;
        }
    
        public String getCity() {
            return city;
        }
    
        public void setCity(String city) {
            this.city = city;
        }
    
        public String getCountry() {
            return country;
        }
    
        public void setCountry(String country) {
            this.country = country;
        }
    
        @Override
        public String toString() {
            return "Address{" +
                    "street='" + street + '\'' +
                    ", city='" + city + '\'' +
                    ", country='" + country + '\'' +
                    '}';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    UML类关系图:
    在这里插入图片描述

    2.实战:获取用户所在的城市

    2.1.直接获取;容易出现空指针异常。

    /**
     * 获取人员所在的城市
     * @author 百里
     */
    public class BaiLiNpeDemo {
        public static void main(String[] args) {
            Address myAddress = new Address();
            User myUser = new User("John Doe", 35, myAddress);
            String city = myUser.getAddress().getCity().trim();
            System.out.println(city);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2.2.使用if-else判断;避免了出现空指针的问题,但是代码结构层次嵌套多,不美观

    /**
     * 使用if进行判断
     * @author 百里
     */
    public class BaiLiSimpleNpeDemo {
        public static void main(String[] args) {
            Address myAddress = new Address();
            User myUser = new User("John Doe", 35, myAddress);
            if (myUser != null) {
                Address address = myUser.getAddress();
                if (address != null) {
                    String city = address.getCity();
                    if (city != null  && !"".equals(city)) {
                        System.out.println("使用if判断字符串:" + "一键三连");
                    }
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    2.3.使用工具类美化一下if判断代码

    /**
     * 使用工具类
     * @author 百里
     */
    public class BaiLiUtilsNpeDemo {
        public static void main(String[] args) {
            Address myAddress = new Address("123 Main St", " Austin ", "CA");
            User myUser = new User("John Doe", 35, myAddress);
            //针对对象与字符串
            if (!ObjectUtils.isEmpty(myUser)) {
                Address address = myUser.getAddress();
                if (!ObjectUtils.isEmpty(address)) {
                    String city = address.getCity();
                    if (!StringUtils.isEmpty(city)) {
                        System.out.println("使用StringUtils工具类判断字符串:" + "一键三连");
                    }
                }
            }
        	//针对数组使用工具类
            ArrayList<User> users = new ArrayList<>();
            users.add(myUser);
            if (!CollectionUtils.isEmpty(users)) {
                System.out.println("使用CollectionUtils工具类判断数组对象:" + "一键三连");
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    2.4.使用Optional解决了层次多的问题也避免了空指针的问题,当我们配合使用orElse时,会先执行orElse方法,然后执行逻辑代码,不管是否出现了空指针。

    /**
     * 使用Optional
     * @author 百里
     */
    public class BaiLiOptionalNpeDemo {
        public static void main(String[] args) {
            Address myAddress = new Address();
            User myUser = new User("John Doe", 35, myAddress);
            System.out.println("使用Optional判断 + orElse:" +
                    Optional.ofNullable(myUser)
                    .map(User::getAddress)
                    .map(Address::getCity)
                    .map(String::trim)
                    .orElse(getDefaultCity())
            );
        }
        //初始化城市
        public static String getDefaultCity() {
            System.out.println("初始化默认城市");
            return null;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    2.5.使用断言处理接口入参,检查假设和前置条件是否满足,以及检查空值情况,提前捕获空指针异常并进行处理

    import org.springframework.util.Assert;
    
    /**
     * 接口参数校验
     * @author 百里
     */
    public class BaiLiAssertNpeDemo {
        public static void main(String[] args) {
            Address myAddress = new Address("123 Main St", " Austin ", "CA");
            User user = new User("John Doe", 35, myAddress);
            getUserCity(user);
            getUserCity(null);
        }
    
        public static void getUserCity(User user){
            Assert.notNull(user,"user is null");
            Address address = user.getAddress();
            Assert.notNull(address,"address is null");
            String city = address.getCity();
            System.out.println(city);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    2.6.使用@Nullable注解,标识变量或方法参数和返回值是否可以为 null,以便在编译期或开发工具中提示可能的 NullPointerException 风险

    /**
     * 使用注解 @Nullable
     * @author 百里
     */
    public class BaiLiNonNullDemo {
        public static void printString(@Nullable String str) {
            System.out.println(str.toString());
        }
    
        @Nullable
        public static String getString() {
            return null;
        }
    
        public static void main(String[] args) {
            String str = null;
            printString(str);
            getString().toString();
    
            User user = new User();
            user.getAddress().getCity();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述

    2.7.额外补充

    JDK17优化了空指针异常信息(Helpful NullPointerExceptions)
    通过精确描述哪个变量为空来提高JVM生成的空指针异常信息的可用性。
    即,以前的空指针异常信息不会告诉你具体是哪个对象为null,当运行的语句是对一个嵌套结构的对象做连续的方法调用(如"a.getb().getc().xxx()")时,就需要进一步分析或调试才能判断出谁是null。而该特性加入以后则直接在异常信息中说明值为null的对象是哪个。

    /**
     * @author 百里
     */
    public class BaiLiNpeDemo {
        public static void main(String[] args) {
            Address myAddress = new Address("123 Main St", null, "CA");
            User myUser = new User("John Doe", 35, myAddress);
            System.out.println(myUser.getAddress().getCity().trim());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    执行结果:

    Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.trim()" because the return value of "npe.Address.getCity()" is null
    	at npe.BaiLiNpeDemo.main(BaiLiNpeDemo.java:16)
    
    • 1
    • 2
  • 相关阅读:
    要写文档了,emmm,先写个文档工具吧——DocMarkdown
    为什么C4D能成为电商设计的王者?
    计算机毕业设计选题推荐-个人健康微信小程序/安卓APP-项目实战
    经典c程序100例==61--100
    移动魔百盒CM311-1sa_ZG代工_S905L3A 安卓9.0 鸿蒙动画_线刷固件包
    Mojo语言的运用
    第九节:类和对象【三】【static、代码块、对象的打印】
    外贸平台效果太差,要不要转型做独立站
    leetcode 14. 最长公共前缀
    【UCAS自然语言处理作业一】利用BeautifulSoup爬取中英文数据,计算熵,验证齐夫定律
  • 原文地址:https://blog.csdn.net/u011305680/article/details/134534300