📜  Java中的空指针异常

📅  最后修改于: 2020-04-05 11:25:21             🧑  作者: Mango

NullPointerException是RuntimeException。在Java中,可以将特殊的null值分配给对象引用。当程序尝试使用具有空值的对象引用时,将引发NullPointerException。
这些可以是:

  • 从空对象调用方法。
  • 访问或修改空对象的字段。
  • 获取null的长度,就好像它是一个数组一样。
  • 访问或修改空对象的插槽,就好像它是一个数组一样。
  • 抛出null,就好像它是Throwable值一样。
  • 当您尝试通过空对象进行同步时。

为什么我们需要空值?
Null是Java中使用的特殊值,它主要用于指示未将值分配给参考变量。null的一种应用是实现数据结构,如链表和树。其他应用包括空对象模式Singleton模式。Singleton模式可确保仅创建一个类的实例,并且还旨在提供对对象的全局访问。
创建一个类的最多一个实例的一种示例方法是将其所有构造函数声明为私有,然后创建一个返回该类的唯一实例的公共方法:

// 使用randomUUID函数
import java.util.UUID;
import java.io.*;
class Singleton
{
    // 初始化值为null
    private static Singleton single = null;
    private String ID = null;
    private Singleton()
    {
        // 使之成为private, 防止创建新的Singleton类对象
        // 创建一个随机ID
        ID = UUID.randomUUID().toString();
    }
    public static Singleton getInstance()
    {
        if (single == null)
            single = new Singleton();
        return single;
    }
    public String getID()
    {
        return this.ID;
    }
}
// 测试代码
public class TestSingleton
{
    public static void main(String[] args)
    {
        Singleton s = Singleton.getInstance();
        System.out.println(s.getID());
    }
}

输出:

10099197-8c2d-4638-9371-e88c820a9af2

在上面的示例中,单例类是静态实例。该实例最多在Singleton getInstance方法内初始化一次。

如何避免NullPointerException?
为了避免NullPointerException,我们必须确保在使用它们之前正确初始化了所有对象。声明引用变量时,必须从对象请求方法或字段之前,验证对象不为null。
以下是解决该问题的解决方案的常见问题。

情况1:字符串与文字的比较
一个非常常见的案例问题涉及String变量和文字之间的比较。文字可以是字符串,也可以是枚举的元素。与其从null对象中调用该方法,不如从文字中调用它。

// Java展示调用null,抛出异常NullPointerException
import java.io.*;
class GFG
{
    public static void main (String[] args)
    {
        // 初始化string变量,使用null
        String ptr = null;
        // 检查ptr是否为null
        try
        {
            // 如下抛出异常NullPointerException
            // 因为ptr为null
            if (ptr.equals("gfg"))
                System.out.print("一样");
            else
                System.out.print("不一样");
        }
        catch(NullPointerException e)
        {
            System.out.print("NullPointerException被捕获");
        }
    }
}

输出:

NullPointerException被捕获

NullPointerException Caught

// Java程序,展示如何避免
// NullPointerException
import java.io.*;
class GFG
{
    public static void main (String[] args)
    {
        // 初始化string变量
        String ptr = null;
        // 使用try-catch检查ptr是否是null
        try
        {
            if ("gfg".equals(ptr))
                System.out.print("一样");
            else
                System.out.print("不一样");
        }
        catch(NullPointerException e)
        {
            System.out.print("NullPointerException被捕获");
        }
    }
}
输出:
不一样

情况2:检查方法的参数

在执行新方法的主体之前,我们应该首先检查其参数是否为空值,然后仅在正确检查参数之后才继续执行该方法。否则,它将抛出IllegalArgumentException并通知调用方法所传递的参数有问题。

// Java程序,展示我们需要在使用参数之前,检查参数是否为null.
import java.io.*;
class GFG
{
    public static void main (String[] args)
    {
        // 空string
        String s = "";
        try
        {
            System.out.println(getLength(s));
        }
        catch(IllegalArgumentException e)
        {
            System.out.println("IllegalArgumentException caught");
        }
        // 调用getLength()
        s = "芒果文档";
        try
        {
            System.out.println(getLength(s));
        }
        catch(IllegalArgumentException e)
        {
            System.out.println("IllegalArgumentException被捕获");
        }
        // 把s设定为null,调用getLength()
        s = null;
        try
        {
            System.out.println(getLength(s));
        }
        catch(IllegalArgumentException e)
        {
            System.out.println("IllegalArgumentException被捕获");
        }
    }
    // Function to return length of string s. It throws
    // IllegalArgumentException if s is null.
    public static int getLength(String s)
    {
        if (s == null)
            throw new IllegalArgumentException("参数不能为null");
        return s.length();
    }
}

输出:

0
13
IllegalArgumentException被捕获

 

情况3:使用三元运算符

三元运算符可用于避免NullPointerException。首先,对布尔表达式求值。如果表达式为true,则返回value1,否则返回value2。我们可以使用三元运算符来处理空指针:

// Java使用三元运算符来避免NullPointerException.
import java.io.*;
class GFG
{
    public static void main (String[] args)
    {
        // 初始化变量,使用null
        String str = null;
        String message = (str == null) ? "" :
                          str.substring(0,5);
        System.out.println(message);
        // 初始化String variable,使用null
        str = "芒果文档";
        message = (str == null) ? "" : str.substring(0,5);
        System.out.println(message);
    }
}

输出:

芒果

如果在情况1中str的引用为null,则消息变量将为空。否则,如果str指向实际数据,则在情况2中,消息将检索其前6个字符。