什么是 NullPointerException,怎么修复它?

什么是java.lang.NullPointerException,这种异常怎么出现的?
用什么方法来防止异常导致程序过早终止?

对象为空,会报空指针,解决办法,解决看对象是否有值

NNE 是 面向对象常见的异常,即一个对象为 null 但是调用了 . 操作。
解决办法:凡是用到对象 . 操作的地方,先 if( xxx ! = null ){} 将 . 操作包裹在 if 判断里面。
Java 8 提供一个高级语法判空的,可以不用手工判断,具体可以自己了解一下。

NullPointerException是一种异常,当您尝试使用指向内存中的(null)的引用时发生的异常,就像正在引用一个对象一样。对空引用调用方法或尝试访问空引用的字段将触发 NullPointerException 。演示一下NullPointerException :

public class Example {
    public static void main(String[] args) {
        Object obj = null;
        obj.hashCode();
    }
}

在main 内部的第一行,我将 Object 引用 obj ,设置为 null。所以,有一个引用,但它不指向任何对象。在此之后,通过调用对象上的方法,将引用视为指向对象。 于是乎NullPointerException就出现了,因为在引用所指向的位置没有要执行的代码。
(这是一个技术性问题,但我认为值得一提的是: 指向 null 的引用不同于指向无效内存位置的 C pointer。 空指针实际上不指向任何地方,这与指向碰巧无效的位置稍有不同。)

当您确定一个引用变量(例如一个对象)时,您实际上是在创建一个指向对象的指针。 看看下面的代码,其中确定一个基本类型为 int变量:

int x;
x = 10;

在这里,变量x 是一个 int ,Java 将其初始化为0。 当您在第二行赋值10 时,Java把赋值写入 x 引用的内存位置。
但是,当您确定引用类型时,情况有所不同。看下面的代码

Integer num;
num = new Integer(10);

第一行确定了一个 num变量,但是它实际上还不包含一个原语值。相反,它包含一个指针(因为类型是Integer,这是一个引用类型)。由于还没有说要指向什么,Java 将其设置为null,这意味着指向的内容为空。
在第二行中,new 关键字用于实例化(或创建) Integer 类型的对象,并将指针变量num 分配给该Integer 对象。
当确定了变量,但没有创建对象时,就会发生NullPointerException 。所以你指向的东西实际上并不存在。
如果在创建对象之前尝试取消引用 num ,则会有NullPointerException。在最普通的情况下,编译器会捕捉到问题,告诉你“ num may not have been initialized” ,但有时可能写一些代码,不直接创建对象。
例如,用下面的方法:

public void doSomething(SomeObject obj) {
   //do something to obj}

在这种情况下,您不是在创建对象 obj,而是假设它是在调用 doSomething()之前创建的。可以这样调用:
doSomething(null);
在这种情况下,obj 为 null。如果目的是对传入的对象执行某些操作,那么出现 NullPointerException 也没什么不合理,因为这是一个程序员错误,程序员为了调试目的需要这些信息。
或者,在某些情况下,目的不仅仅是对传入的对象进行操作,因此可以接受空参数。 在这种情况下,您需要检查空参数并采取不同的方法。 还应该在文档中解释这一点。 例如,doSomething() 这样写:

/**
  * @param obj An optional foo for ____. May be null, in which case 
  *  the result will be ____.
  */public void doSomething(SomeObject obj) {
    if(obj != null) {
       //do something
    } else {
       //do something else
    }}

首先,什么是 NullPointerException?
从 JavaDocs开始说起吧。包括以下内容:
当应用程序在需要对象的情况下尝试使用 null 时引发。包括:
• 调用null object
• 访问或修改null object的字段
• 将 null 的长度当作数组来计算
• 访问或修改 null 插槽,把它当成数组
• Throw null就好像它是 Throwable 值一样
如果您尝试使用带 synchronized的 null 引用,也会引发这个异常,per the JLS:
SynchronizedStatement:
synchronized ( Expression ) Block
• 否则,如果表达式的值为null,则出现NullPointerException
其次,我该怎么修复它?
已经出现了NullPointerException怎么解决?下面举个 NullPointerException的栗子哈:

public class Printer {
    private String name;
    public void setName(String name) {
        this.name = name;
    }
    public void print() {
        printString(name);
    }
    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }
    public static void main(String[] args) {
        Printer printer = new Printer();
        printer.print();
    }}

首先,标识null值
第一步是确定哪些值导致了异常。 为此,我们需要进行一些调试。 读 stacktrace 是很重要的。从中能看出异常是在哪里出现的:

Exception in thread "main" java.lang.NullPointerException
    at Printer.printString(Printer.java:13)
    at Printer.print(Printer.java:9)
    at Printer.main(Printer.java:19)

这里,我们看到在第13行出现异常(在printString 中)。通过添加日志语句或使用调试器,查看该行并检查哪些为 null。 我们发现 s 是 null,然后调用它上的length 出现异常。我们可以看到,当从中删除 s.length() 时,程序停止抛出异常。
第二步,这些value哪儿来的?
下一步检查,这个值从哪里来。通过跟踪调用,可以看到,在print()中,s 与printString(name) 一起传入, this.name为 null。
第三步,跟踪这些值应该设置在哪里
this.name放在哪里? 在setName(String)中。 通过更多的调试,我们可以看到根本没有被调用。如果调用了,请确保检查调用顺序,并且在用了 print 后不用 set 。
This is enough to give us a solution: add a call to before calling .
所以解决方案就是: 在调用printer.print() 之前,向printer.setName() 添加一个调用。
其他补救措施
变量可以有一个默认值(setName 可以防止它被设置为 null) :
private String name = "";
或者 printString方法可以检查 null,例如:
printString((name == null) ? "" : name);
或者你可以设计这个类,让它的名字总是有一个非空值:

public class Printer {
    private final String name;
    public Printer(String name) {
        this.name = Objects.requireNonNull(name);
    }
    public void print() {
        printString(name);
    }
    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }
    public static void main(String[] args) {
        Printer printer = new Printer("123");
        printer.print();
    }}