那些年我们一起追过的空指针Chapter01到底什么是

Chapter 01 到底什么是空指针异常?

  空指针会出现在很多语言中,java中空指针异常指的是java.lang.NullPointException,我们都知道对象是保存在内存中的空指针异常中,空是内存地址为空,指针则是指该对象被别的对象指向或引用,当引用时就会爆出异常对象(引用数据类型)如果没有初始化操作就是null,这就是产生空指针异常的根本原因

image.png

Section 01 常见空指针异常

模拟空指针异常的场景
新建一个maven项目
新增package com.citi.npe
创建NpeApplication,新增main方法

public class NpeApplication {

    public static void main(String[] args) {

    }
}    
复制代码

创建entity包,新增User实体类

public class User {

    public String name;
    public String[] books;

    public void say(){
        System.out.println("This is say method");
    }

    public String readBook(){
        System.out.println("This is read book method");
        return null;
    }
}
复制代码

现象1:访问了空对象的属性

public static void callNullObjectAttribute(){
    User user = null;
    System.out.println(user.name);
}
复制代码

在main方法中调用callNullObjectAttribute(),控制台打印空指针异常

image.png

现象2:调用了空对象的实例方法

public static void callNullObjectMethod(){
    User user = null;
    user.say();
}
复制代码

在main方法中调用callNullObjectMethod(),控制台打印空指针异常

image.png

现象3:当数组是一个空对象的时候,取他的长度

public static void getLenFromNullArray(){
    User user = null;
    System.out.println(user.books.length);
}
复制代码

在main方法中调用getLenFromNullArray(),控制台打印空指针异常

image.png

现象4:抛出空的运行时异常

新增exception包,新增CustException自定义运行时异常类,并继承RuntimeException

public static void throwNullException(){
    CustException custException = null;
    throw custException;
}
复制代码

在main方法中调用throwNullException(),抛出空指针异常

image.png

现象5: 对方法返回的空对象进行操作

public static void opNullObjReturnFromMethod(){
    User user = null;
    System.out.println(user.readBook().contains("book"));
}
复制代码

在main方法中调用opNullObjReturnFromMethod(),控制台打印出空指针异常
image.png

如何避免空指针异常

  • 使用对象之前一定要进行初始化,或者对是否初始化进行校验
  • 不要设置函数返回值为null
  • 针对接收的对象一定要进行判断

Section 02 赋值自动拆箱空指针异常

赋值时自动拆箱出现空指针异常

image.png

自动拆箱引发的空指针

  • 变量赋值自动拆箱引发空指针
  • 方法传递参数自动拆箱引发空指针

在npe包下新建UnboxingNpeApplication

public class UnboxingNpeApplication {

    public static void main(String[] args) {


    }
}    
复制代码

变量赋值时自动拆箱的空指针异常

public static void assignValueByUnboxing(){
    Integer i = null;
    int i_01 = i;
    System.out.println(i_01);
}
复制代码

main方法中调用assignValueByUnboxing(),控制台打印出空指针报错信息

image.png

方法传参时自动拆箱空指针异常

public static void passArguByUnboxing(){
    Integer x = null;
    Integer y = null;
    add(x,y);
}

public static int add(int x, int y){
    return x + y;
}
复制代码

main方法中调用passArguByUnboxing(),控制台打印报错信息如下

image.png

规避空指针异常的建议

  • 基本数据类型和引用数据类型,优先考虑基本数据类型
  • 对于不确定的包装器类型进行判断校验
  • 对于值为null的包装起赋值为0

Section 03 - 集合出现空指针的情况

新增CollectionNpeApplication,并添加main方法

字符串使用equals()方法比较时空指针

public static boolean isEqualStringAndNull(String x, String y){
    return x.equals(y);
}
复制代码

在main方法中调用

public static void main(String[] args) {
    // 常量.equals(变量)
    boolean isEqual = isEqualStringAndNull("abc",null);
    System.out.println(""abc"与null比较:" + isEqual);
    boolean isEqual1 = isEqualStringAndNull(null,"abc");
    System.out.println("null与"abc"比较:" + isEqual1);
}
复制代码

控制台打印如下null.equals("abc")爆了空指针报错,字符串与null使用equals()方法比较时,变量放在equals()方法参数中,方式变量为null时报空指针异常
image.png

操作对象对象数组中的空对象时空指针
在测试类中新增方法

public static void emptyObjectArray(){
    User[] userList = new User[5];
    for (int i = 1; i <= userList.length; i++) {
        // userList[i] 为null,自然不能通过.属性的方式赋值
        userList[i].name = "stark no." + i;
    }
}
复制代码

执行该静态方法,userList[i] 为null,通过.属性的方式赋值也会报错空指针
image.png

List,ArrayList执行addAll(null)时空指针
image.png
查看ArrayList的addAll()方法的源码

image.png

这里使用了toArray()方法,由于参数本身是null,所以执行会报错
image.png