从零开始学Java之大名鼎鼎的NullPointerException到底该怎么处理?
前言
在上一篇文章中,壹哥给大家讲解了该如何自定义异常,以及如何处理自定义异常。接下来壹哥会带大家再来单独看一个很常见的异常--空指针异常,这个可以说是每个Java程序员都必知的异常,所以我们不得不单独学习一下。
------------------------------前戏已做完,精彩即开始----------------------------
全文大约【2700】 字,不说废话,只讲可以让你学到技术、明白原理的纯干货!本文带有丰富的案例及配图视频,让你更好地理解和运用文中的技术概念,并可以给你带来具有足够启迪的思考......
配套开源项目资料
Github: github.com/SunLtd/Lear…
Gitee: 一一哥/从零开始学Java
一. 简介
你要问壹哥,Java中哪个异常最有名,那就不得不说NullPointerException!
NullPointerException,空指针异常,简称为NPE。这对Java程序员来说,可以说是一个无人不知、无人不晓的异常了!空指针异常往往是由于程序员没有考虑到变量或者对象的值可能为null,或者没有对null值进行判断导致的。所以当我们试图访问null对象或者是对null对象进行操作时,就会抛出NullPointerException异常。
NullPointerException异常在运行时被抛出,如果不加以处理,会导致程序的中断或者崩溃,因此我们在编写Java程序时,要格外注意避免空指针异常的发生。
二. 产生原因
之所以会出现NullPointerException空指针异常,最根本的原因只有一个,那就是”对象为空“ ,这和很多单身狗的毛病一样,hiahia😺。也就是说,当一个对象为null时,你还非得调用该对象的方法或字段,此时JVM就会产生NullPointerException,例如:
public static void main(String[] args) {
String s = null;
System.out.println(s.toUpperCase());
}
当上面这段代码运行时,肯定会产生空指针异常,因为对象”s“是null。也就是我们没有给该对象初始化赋值,它就是一个空壳子,你还非要使用它,这时就会出事。
三. 典型情况
虽然我们现在已经知道引发空指针异常的原因了,但为了让大家避免这种常见的异常,壹哥还是想给大家列举几个会引发空指针异常的典型情况。
3.1 对空对象调用方法或访问属性
当一个对象为null时,它就没有任何属性和方法,如果我们在这个空对象上调用方法或访问属性,就会引发空指针异常。例如:
String str = null;
int length = str.length(); // 会抛出空指针异常
3.2 数组元素为null
在Java中,数组中的元素也可能会为null。如果我们在一个null数组元素上调用方法或访问属性,同样会抛出空指针异常。例如:
String[] strs = new String[3];
strs[0] = "Hello";
strs[1] = null;
int length = strs[1].length(); // 会抛出空指针异常
3.3 参数为null
在调用方法时,如果参数为null,而方法内部却需要使用这个参数,也会抛出空指针异常。例如:
public void printString(String str) {
System.out.println(str.length());
}
String str = null;
printString(str); // 会抛出空指针异常
四. 解决办法
为了避免空指针异常的发生,我们需要加强对变量和对象的判断,如果发现其值为null,就需要及早进行处理,例如设置默认值或者抛出异常。我们要知道,NullPointerException其实是一种代码逻辑错误,遇到NullPointerException,要遵循”早暴露、早修复“的原则,不要使用catch语句来隐藏这种编码错误! 比如下面这样的代码就不行:
// 错误示例: 捕获NullPointerException
try {
transferMoney(from, to, amount);
} catch (NullPointerException e) {
//不要去捕获空指针异常!
}
接下来壹哥给大家列举几个常用的避免空指针异常的方法。
4.1 使用条件判断语句
通过判断变量是否为null,可以避免空指针异常的发生。例如:
String str = null;
if (str != null) {
int length = str.length();
}
4.2 使用对象初始化语句
我们在使用对象之前,确保要对该对象进行初始化,这样就可以保证对象不为null。例如:
String str = "";
int length = str.length();
我们在编写业务逻辑时,使用空字符串""表示未填写,而不要用默认的null,""空串要比null安全得多,这可以避免很多NullPointerException。
4.3 使用Objects.requireNonNull()方法
Objects.requireNonNull()方法可以判断参数是否为null,如果是null,则会抛出NullPointerException异常。例如:
String str = null;
Objects.requireNonNull(str, "str不能为空"); // 会抛出NullPointerException异常
4.4 返回空数组
如果我们使用数组时,某个数组没有数据,此时可以返回一个元素为空的数组,但是不要返回null,比如:
public String[] getData(String item) {
if (getItem(item) == 0) {
// 返回空数组而不是null:
return new String[0];
}
...
}
这样调用方就不用检查结果是否为null。
4.5 使用Optional
Optional是Java 8中引入的一个非常有用的类,用于解决null值问题。它是一个容器对象,可能包含非空值或空值,主要目的是减少代码中的空指针异常,当调用方一定要判断某个对象是否为null时,就可以考虑使用Optional。接下来壹哥给大家编写一个简单的Optional案例。
import java.io.IOException;
import java.util.Optional;
/**
* @author 一一哥Sun
*/
public class Demo13 {
public static void main(String[] args) throws IOException {
String str="一一哥";
//创建一个包含非空值的Optional对象。如果传入的值为null,则会抛出NullPointerException异常。
Optional<String> optional = Optional.of(str);
if(optional.isPresent()) {
String value = optional.get();
System.out.println("value="+value);
}else {
System.out.println("字符串为空");
}
//ofNullable方法
String name = null;
//Optional.ofNullable静态工厂方法,创建一个包含指定值的Optional对象,如果传入的值为null,则返回一个空的Optional对象
Optional<String> optionalName = Optional.ofNullable(name);
String orElse = optionalName.orElse("Unknown");
System.out.println("值="+orElse);
}
}
我们可以使用 Optional.of 静态工厂方法来创建一个包含非空值的 Optional 对象,如果传入的值为 null,则会抛出 NullPointerException 异常。并可以使用 isPresent() 方法来判断 Optional 对象是否包含非空值。如果包含非空值,则返回 true,否则返回 false。
也可以使用 Optional.ofNullable 静态工厂方法,来创建一个包含指定值的 Optional 对象,如果传入的值为 null,则会返回一个空的 Optional对象。然后使用 orElse() 方法来获取 Optional 对象中包含的值,如果 Optional 对象为空,则返回指定的默认值。
关于Optional的用法还有很多,以后壹哥会出一个Java新特性的专题系列,这里就不再细说了,敬请期待哦。
4.6 定位空指针异常
当我们编写的代码真的产生了空指针异常,那该怎么办呢?壹哥前面就跟大家说过,产生空指针异常的根本原因就是因为”对象为空“,所以解决的办法就是先找到这个为空的对象,然后给这个对象赋值,只要对象不为空,这个空指针异常就解决了。听起来也不难,但真的开发时,有时候经验不丰富的程序员,可能一时半会还找不到是哪个对象为空了。因为我们的项目中,对象实在太多了!比如下面这样的代码:
a.b.c.method()
这里的a、b、c都是对象,假如就是这一行代码产生了空指针,你说到底是哪个对象为空?有可能是a为空,也有可能是b,也有可能是c,通常我们得一个对象一个对象进行判断,比如通过打印日志进行判断:
System.out.println(a);
System.out.println(a.b);
System.out.println(a.b.c);
但是这样写代码,就显得啰嗦且低效!为了改善这种问题,在JDK 14中推出了新的API,JVM可以直接给出详细的信息,告诉我们null对象到底是哪个。在JDK 14中,如果是上面的代码产生了空指针异常,会出现这样的提示信息:... because "....a.b" is null....
意思是b对象为null。但该功能默认是关闭的,我们需要给JVM添加一个-XX:+ShowCodeDetailsInExceptionMessages
参数启用它,如下:
java -XX:+ShowCodeDetailsInExceptionMessages Main.java
以上就是壹哥列举出来的几种避免及检查空指针异常的常用方法,希望你可以掌握。
总之,我们在编写Java程序时,要格外注意避免空指针异常的发生,加强对变量和对象的判断,养成良好的编码习惯,就可以极大地降低NullPointerException的产生。如果发现值为null,就需要及早进行处理,避免程序中断或者崩溃。
------------------------------正片已结束,来根事后烟----------------------------
五. 结语
这样,壹哥就把空指针这种特别常见的异常单独给大家分析了一下,希望大家以后遇到这种异常能够知道怎么解决。今天的重点内容如下:
- NullPointerException的根本原因是对象为空;
- 对空指针异常要早暴露,早修复,不要使用catch进行捕获;
- 可以启用Java 14的增强异常来定位空指针异常的产生位置。
另外如果你独自学习觉得有很多困难,可以加入壹哥的学习互助群,大家一起交流学习。
转载自:https://juejin.cn/post/7273025863980384256