你有没有掉进去过这些 Exception 的“陷阱”(Part A)

简介: 你有没有掉进去过这些 Exception 的“陷阱”(Part A)

一、到底什么是空指针异常

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

b3ed0b70528b4a929b6999cbeee6aaea_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

二、常见空指针异常

新建maven项目 exception-traps,增加junit和lombok依赖

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13.2</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.24</version>
    <scope>provided</scope>
</dependency>
复制代码

创建com.lilith.traps.entity包,新增User实体类

@Data
public class User {
    public String name;
    public String[] books;
    public String say(){
        System.out.println("say()方法被调用了");
        return null;
    }
    public void readBook(){
        System.out.println("readBook()方法被调用了");
    }
}
复制代码

现象1:访问了空对象的成员方法

在test包下创建com.lilith.traps.NullPointExceptionTest测试类

public class NullPointExceptionTest {
    @Test
    public void testCallNullObjMethod(){
        User user = null;
        user.readBook();
    }
}
复制代码

在测试类中调用testCallNullObjMethod(),控制台打印空指针异常

1cf09ed2e4bc439f82109fc9a62290f2_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

现象2:调用了空对象的属性

在NullPointExceptionTest中增加方法testCallNullObjAttr(),测试空指针时调用对象属性

@Test
public void testCallNullObjAttr(){
    User user = null;
    user.getName();
}
复制代码

在测试类中执行testCallNullObjAttr(),控制台打印空指针异常

image.png

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

@Test
public void testGetLenOfNullList(){
    User user = new User();
    System.out.println(user.books.length);
}
复制代码

testGetLenOfNullList(),控制台打印空指针异常

image.png

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

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

public class LilithException extends RuntimeException {
}
复制代码

在NullPointExceptionTest测试类中新增方法testThrowNullException()

@Test
public void testThrowNullException(){
    LilithException lilithException = null;
    throw lilithException;
}
复制代码

执行testThrowNullException(),抛出空指针异常

image.png

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

在NullPointExceptionTest测试类中新增方法testHandleNullObjectOfMethodReturn()

@Test
public void testHandleNullObjectOfMethodReturn(){
    User user = new User();
    System.out.println(user.say().concat("Hello"));
}
复制代码

执行testHandleNullObjectOfMethodReturn(),控制台打印出空指针异常

image.png

如何避免空指针异常

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

三、自动拆箱空指针异常

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

Java中的8中基本数据类型都会对应一个包装类

  • 装箱:基本类型转变为包装器类型的过程,装箱是通过调用包装器类的 valueOf 方法实现的
  • 拆箱:包装器类型转变为基本类型的过程,拆箱是通过调用包装器类的 xxxValue 方法实现的,xxx代表对应的基本数据类型。

image.png

自动拆箱引发的空指针:

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

现象7:变量赋值时自动拆箱的空指针异常

在test包下新建UnboxingNullPointExceptionTest,新增testAssignValueWhenUnboxing()方法

public class UnboxingNullPointExceptionTest {
    @Test
    public void testAssignValueWhenUnboxing(){
        Long count = null;
        long count_ = count;
        System.out.println(count_);
    }
}
复制代码

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

image.png

现象8:方法传参时自动拆箱空指针异常

在UnboxingNullPointExceptionTest测试类中定义一个add()方法,传入两个基本类型的x和y,新建测试方法testInputArgumentsByUnboxing(),在方法中调用add方法,并传入包装类

public static int add(int x, int y){
    return x + y;
}
@Test
public void testInputArgumentsByUnboxing(){
    Integer x = null;
    Integer y = null;
    add(x, y);
}
复制代码

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

image.png

现象9:大小比较时自动拆箱空指针异常

在UnboxingNullPointExceptionTest测试类中定义一个compare()方法,传入两个基本类型的x和y,新建测试方法testCompareValueByUnboxing(),在方法中调用compare方法,并传入包装类

public static boolean compare(int x, int y){
    return x >= y;
}
@Test
public void testCompareValueByUnboxing(){
    Integer x = 1;
    Integer y = null;
    compare(x, y);
}
复制代码

执行testCompareValueByUnboxing()方法

image.png

规避空指针异常的建议

拆箱是通过调用包装器类的 xxxValue 方法实现的,也就是说当包装类为空时调用方法就会出现空指针异常

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

四、String、ArrayList 的空指针情况

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

新建测试类StringNullPointExceptionTest,新增测试方法testStringEqual()

public class StringNullPointExceptionTest {
    @Test
    public void testStringEqual(){
        String name = null;
        System.out.println(name.equals("stark"));
    }
}
复制代码

执行该方法

image.png

控制台打印出空指针异常,这种情况就相当于与空对象调用属性,所以会出现空指针异常

非null字符串与可能为null的字符串使用equals()方法比较时,应该将可能为null的字符串放在equals()方法参数中,才能够进行比较,将最后一句代码替换为

System.out.println("stark".equals(name));
复制代码

再次执行

image.png

控制台正常

现象11:操作对象数组中的空对象时空指针

在测试类中新增测试类ListNullPointExceptionTest,增加测试方法testHandleNullElementOfList()

public class ListNullPointExceptionTest {
    @Test
    public void testHandleNullElementOfList(){
        User[] userList = new User[5];
        for (int i = 0; i < 4; i++) {
            userList[i].name = "Mark " + i;
        }
    }
}
复制代码

执行该方法

image.png

userList[i] 为null,通过.属性的方式赋值会报错空指针

现象12:ArrayList执行addAll(null)时空指针

在ListNullPointExceptionTest测试类中新增方法

@Test
public void testAddNullElementToList(){
    List<User> userList = new ArrayList<>();
    Collection<User> users = null;
    userList.addAll(users);
}
复制代码

执行该方法

image.png

控制台出现空指针异常

查看ArrayList的addAll()方法的源码

image.png

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

image.png


相关文章
|
5天前
震惊!!!return 语句居然是这样的
震惊!!!return 语句居然是这样的
11 1
|
Java 开发者 容器
【Java挠头】Java异常、捕获、处理、throw、throws等绝妙剖析
【Java挠头】Java异常、捕获、处理、throw、throws等绝妙剖析
127 0
【Java挠头】Java异常、捕获、处理、throw、throws等绝妙剖析
|
Java API 容器
你有没有掉进去过这些 Exception 的“陷阱“(Part B)
你有没有掉进去过这些 Exception 的“陷阱“(Part B)
你有没有掉进去过这些 Exception 的“陷阱“(Part B)
|
Java 数据库连接
你有没有掉进去过这些 Exception 的“陷阱“(Part C)
你有没有掉进去过这些 Exception 的“陷阱“(Part C)
你有没有掉进去过这些 Exception 的“陷阱“(Part C)
|
Serverless C语言 Python
学编程这么久,还傻傻分不清什么是方法(method),什么是函数(function)?
在标准库inspect 中,它提供了两个自省的函数,即 ismethod() 和 isfunction(),可以用来判断什么是方法,什么是函数。
271 0
学编程这么久,还傻傻分不清什么是方法(method),什么是函数(function)?
|
JSON 数据格式 Python
Error: 待解决bug
Error: 待解决bug
|
Java
再也不要对java中==和equals的区别有困惑了,这篇文章保证你能懂
想到你应该无数次看到过这个问题了,也可能你已经看过无数篇文章了,如果你还是一头雾水或者是不理解,那试着看看这篇文章,相信你一定能看懂。
93 0
再也不要对java中==和equals的区别有困惑了,这篇文章保证你能懂
|
Java
Continue与Break在使用过程中的爱恨情仇| Java Debug 笔记
Continue与Break在使用过程中的爱恨情仇| Java Debug 笔记
83 0
重构——56以测试取代异常(Replace Exception with Test)
以测试取代异常(Replace Exception with Test):面对一个调用者可以预先检查的条件,你抛出了一个异常;修改调用者,使它在调用函数之前先做检查
1275 0