likes
comments
collection
share

从零开始学Java之大名鼎鼎的NullPointerException到底该怎么处理?

作者站长头像
站长
· 阅读数 25

前言

在上一篇文章中,壹哥给大家讲解了该如何自定义异常,以及如何处理自定义异常。接下来壹哥会带大家再来单独看一个很常见的异常--空指针异常,这个可以说是每个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的增强异常来定位空指针异常的产生位置。

另外如果你独自学习觉得有很多困难,可以加入壹哥的学习互助群,大家一起交流学习。