一、到底什么是空指针异常
空指针会出现在很多语言中,java中空指针异常指的是java.lang.NullPointException,我们都知道对象是保存在内存中的空指针异常中,空是内存地址为空,指针则是指该对象被别的对象指向或引用,当引用时就会爆出异常对象(引用数据类型)如果没有初始化操作就是null,这就是产生空指针异常的根本原因
二、常见空指针异常
新建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(),控制台打印空指针异常
现象2:调用了空对象的属性
在NullPointExceptionTest中增加方法testCallNullObjAttr(),测试空指针时调用对象属性
@Test public void testCallNullObjAttr(){ User user = null; user.getName(); } 复制代码
在测试类中执行testCallNullObjAttr(),控制台打印空指针异常
现象3:当数组是一个空对象的时候,取它的长度
@Test public void testGetLenOfNullList(){ User user = new User(); System.out.println(user.books.length); } 复制代码
testGetLenOfNullList(),控制台打印空指针异常
现象4:抛出空的运行时异常
新增exception包,新增自定义运行时异常类LilithException,并继承RuntimeException
public class LilithException extends RuntimeException { } 复制代码
在NullPointExceptionTest测试类中新增方法testThrowNullException()
@Test public void testThrowNullException(){ LilithException lilithException = null; throw lilithException; } 复制代码
执行testThrowNullException(),抛出空指针异常
现象5: 对方法返回的空对象进行操作
在NullPointExceptionTest测试类中新增方法testHandleNullObjectOfMethodReturn()
@Test public void testHandleNullObjectOfMethodReturn(){ User user = new User(); System.out.println(user.say().concat("Hello")); } 复制代码
执行testHandleNullObjectOfMethodReturn(),控制台打印出空指针异常
如何避免空指针异常
- 使用对象之前一定要进行初始化,或者对是否初始化进行校验
- 不要设置函数返回值为null
- 针对接收的对象一定要进行判断
三、自动拆箱空指针异常
现象6:赋值时自动拆箱出现空指针异常
Java中的8中基本数据类型都会对应一个包装类
- 装箱:基本类型转变为包装器类型的过程,装箱是通过调用包装器类的 valueOf 方法实现的
- 拆箱:包装器类型转变为基本类型的过程,拆箱是通过调用包装器类的 xxxValue 方法实现的,xxx代表对应的基本数据类型。
自动拆箱引发的空指针:
- 变量赋值自动拆箱引发空指针
- 方法传递参数自动拆箱引发空指针
现象7:变量赋值时自动拆箱的空指针异常
在test包下新建UnboxingNullPointExceptionTest,新增testAssignValueWhenUnboxing()方法
public class UnboxingNullPointExceptionTest { @Test public void testAssignValueWhenUnboxing(){ Long count = null; long count_ = count; System.out.println(count_); } } 复制代码
调用testAssignValueWhenUnboxing()方法,控制台打印出空指针报错信息
现象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()方法,控制台打印报错信息如下
现象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()方法
规避空指针异常的建议
拆箱是通过调用包装器类的 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")); } } 复制代码
执行该方法
控制台打印出空指针异常,这种情况就相当于与空对象调用属性,所以会出现空指针异常
非null字符串与可能为null的字符串使用equals()方法比较时,应该将可能为null的字符串放在equals()方法参数中,才能够进行比较,将最后一句代码替换为
System.out.println("stark".equals(name)); 复制代码
再次执行
控制台正常
现象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; } } } 复制代码
执行该方法
userList[i] 为null,通过.属性的方式赋值会报错空指针
现象12:ArrayList执行addAll(null)时空指针
在ListNullPointExceptionTest测试类中新增方法
@Test public void testAddNullElementToList(){ List<User> userList = new ArrayList<>(); Collection<User> users = null; userList.addAll(users); } 复制代码
执行该方法
控制台出现空指针异常
查看ArrayList的addAll()方法的源码
这里使用了toArray()方法,由于参数本身是null,所以执行会报错