java - numberformatexception意思 - 什麼是NullPointerException,以及如何解決它?




nullpointerexception解決 (8)

什麼是NullPointerException?

JavaDocs是一個很好的開始。 他們涵蓋了這些內容:

當應用程序嘗試在需要對象的情況下使用null時拋出。 這些包括:

  • 調用空對象的實例方法。
  • 訪問或修改空對象的字段。
  • 將null的長度視為數組。
  • 像訪問數組一樣訪問或修改null的槽。
  • 如果它是Throwable值,則拋出null。

應用程序應該拋出此類的實例來指示其他非法使用null對象。

同樣的情況是,如果您嘗試使用帶有synchronized的空引用,那麼也會根據JLS引發此異常:

SynchronizedStatement:
    synchronized ( Expression ) Block
  • 否則,如果Expression的值為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();
    }
}

識別空值

第一步是準確識別哪些值導致異常 。 為此,我們需要做一些調試。 學習閱讀堆棧跟踪很重要。 這會告訴你拋出異常的地方:

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方法中)。 查看該行並通過添加日誌語句或使用調試器來檢查哪些值為空。 我們發現s是空的,調用它的length方法會拋出異常。 當s.length()從方法中移除時,我們可以看到程序停止拋出異常。

跟踪這些值來自哪裡

接下來檢查這個值來自哪裡。 通過跟隨方法的調用者,我們看到sprint()方法中使用printString(name)傳入,並且this.name為null。

跟踪應該設置這些值的位置

this.name在哪裡設置? 在setName(String)方法中。 通過更多的調試,我們可以看到這個方法根本不被調用。 如果調用該方法,請確保檢查這些方法的調用順序 ,並且在打印方法之後不調用set方法。

這足以給我們一個解決方案:在調用printer.setName()之前添加對printer.setName()調用。

其他修補程序

該變量可以有一個默認值 (並且setName可以防止它被設置為null):

private String name = "";

print或者printString方法可以檢查null ,例如:

printString((name == null) ? "" : name);

或者你可以設計這個類,使得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();
    }
}

也可以看看:

我仍然無法找到問題

如果您嘗試調試問題並且仍然沒有解決方案,可以發布一個問題以獲得更多幫助,但請確保包含迄今為止嘗試的內容。 至少在問題中包含堆棧跟踪 ,並在代碼中標記重要的行號 。 另外,請先嘗試簡化代碼(請參閱SSCCE )。

https://code.i-harness.com

什麼是空指針異常( java.lang.NullPointerException )以及導致它們的原因?

可以使用哪些方法/工具來確定原因,以便阻止異常導致程序過早終止?


問題:導致NullPointerException (NPE)的原因是什麼?

正如您應該知道的那樣,Java類型被分為基本類型booleanint等)和引用類型 。 Java中的引用類型允許您使用特殊值null ,這是Java的“無對象”方式。

每當程序嘗試使用null ,就像它是一個真實的引用一樣,運行時拋出NullPointerException 。 例如,如果你寫這個:

public class Test {
    public static void main(String[] args) {
        String foo = null;
        int length = foo.length();   // HERE
    }
}

標記為“HERE”的語句將嘗試在null引用上運行length()方法,這將引發NullPointerException

有很多方法可以使用會導致NullPointerExceptionnull值。 事實上,你可以使用null來做的唯一事情就是不會導致NPE:

  • 將其分配給參考變量或從參考變量讀取它,
  • 將其分配給一個數組元素或從數組元素中讀取它(假設數組引用本身是非空的!),
  • 將它作為參數傳遞或作為結果返回,或者
  • 使用==!=運算符或instanceof對其進行測試。

問題:我如何閱讀NPE堆棧跟踪?

假設我編譯並運行上面的程序:

$ javac Test.java 
$ java Test
Exception in thread "main" java.lang.NullPointerException
    at Test.main(Test.java:4)
$

首先觀察:編譯成功! 程序中的問題不是編譯錯誤。 這是一個運行時錯誤。 (有些IDE可能會警告你的程序總是會拋出一個異常......但標準的javac編譯器不會。)

第二個觀察:當我運行該程序時,它輸出兩行“gobbledy-gook”。 錯誤!! 這不是蠢貨。 它是一個堆棧跟踪...並且它提供了重要的信息 ,如果您花時間仔細閱讀,它將幫助您跟踪代碼中的錯誤。

所以讓我們看看它說什麼:

Exception in thread "main" java.lang.NullPointerException

堆棧跟踪的第一行告訴你許多事情:

  • 它會告訴您引發異常的Java線程的名稱。 對於一個線程簡單的程序(比如這個),它將是“主要”。 讓我們繼續 ...
  • 它會告訴你所拋出異常的全名; 即java.lang.NullPointerException
  • 如果異常具有關聯的錯誤消息,那麼將在異常名稱後輸出。 在這方面, NullPointerException是不常見的,因為它很少有錯誤消息。

第二行是診斷NPE最重要的一條。

at Test.main(Test.java:4)

這告訴我們很多事情:

  • “在Test.main”說我們是Test類的main方法。
  • “Test.java:4”給出了類的源文件名,並且它告訴我們發生這種情況的語句在文件的第4行。

如果你計算上面的文件中的行數,第4行就是我用“HERE”註釋標記的行數。

請注意,在更複雜的示例中,NPE堆棧跟踪中會有很多行。 但是你可以確定第二行(第一個“at”行)會告訴你NPE在哪裡被拋出1

簡而言之,堆棧跟踪將清楚地告訴我們程序的哪個語句拋出了NPE。

1 - 不完全正確。 有些東西叫做嵌套異常...

問題:我如何在代碼中找出NPE異常的原因?

這是困難的部分。 簡短的答案是對堆棧跟踪,源代碼和相關API文檔提供的證據進行邏輯推理。

我們首先用簡單的例子(上面)來說明。 我們首先看堆棧跟踪告訴我們的是NPE發生的地方:

int length = foo.length(); // HERE

那怎麼能拋出一個NPE?

事實上,只有一種方法:只有當foo的值為null才會發生。 然後我們嘗試在null和.... BANG上運行length()方法。

但是(我聽到你說)如果NPE在length()方法調用中被拋出怎麼辦?

那麼,如果發生這種情況,堆棧跟踪看起來會不一樣。 第一個“at”行會說異常在java.lang.String類的某一行中引發, Test.java的第4行將是第二個“at”行。

那麼null從哪裡來? 在這種情況下,很明顯,我們需要做的是修復它。 (為foo分配一個非空值。)

好的,讓我們來嘗試一個稍微棘手的例子。 這將需要一些合理的扣除

public class Test {

    private static String[] foo = new String[2];

    private static int test(String[] bar, int pos) {
        return bar[pos].length();
    }

    public static void main(String[] args) {
        int length = test(foo, 1);
    }
}

$ javac Test.java 
$ java Test
Exception in thread "main" java.lang.NullPointerException
    at Test.test(Test.java:6)
    at Test.main(Test.java:10)
$ 

所以現在我們有兩條“at”線。 第一個是這一行:

return args[pos].length();

第二個是這條線:

int length = test(foo, 1);

看第一行,怎麼會拋出NPE? 有兩種方法:

  • 如果bar值為null bar[pos]會拋出一個NPE。
  • 如果bar[pos]值為null那麼調用length()將拋出一個NPE。

接下來,我們需要弄清楚哪些場景解釋了實際發生的情況。 我們將從探索第一個開始:

bar從哪裡來? 它是test方法調用的一個參數,如果我們看看如何調用test ,我們可以看到它來自foo靜態變量。 另外,我們可以清楚地看到,我們將foo初始化為一個非空值。 這足以暫時駁回這種解釋。 (理論上,其他東西可能會將foo改為null ...但這不會發生在這裡。)

那麼我們的第二種情況呢? 那麼,我們可以看到pos1 ,所以這意味著foo[1]必須為null 。 那可能嗎?

它的確是! 這就是問題所在。 當我們像這樣初始化時:

private static String[] foo = new String[2];

我們用兩個初始化為null元素分配一個String[] 。 之後,我們沒有改變foo的內容......所以foo[1]仍然是null


NullPointerException是當您嘗試使用指向內存中沒有位置的引用(空)時發生的異常,就好像它正在引用對像一樣。 在空引用上調用方法或嘗試訪問空引用的字段將觸發NullPointerException 。 這些是最常見的,但在NullPointerException javadoc頁面上列出了其他方法。

可能是我可以用來說明NullPointerException的最快的示例代碼是:

public class Example {

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

}

main的第一行,我明確地將Object reference obj設置為null 。 這意味著我有一個參考,但它不指向任何對象。 在那之後,我嘗試將引用視為通過調用一個方法來指向一個對象。 這會導致NullPointerException因為在引用指向的位置沒有要執行的代碼。

(這是一個技術性問題,但我認為它提到了:指向null的引用與指向無效內存位置的C指針不同。空指針實際上並不指向任何地方 ,這與指向不同的指向一個恰好無效的位置。)


Java ,你聲明的所有變量實際上是對象(或基元)的“引用”,而不是對象本身。

當您嘗試執行一個對象方法時,引用會要求活動對象執行該方法。 但是如果引用是引用NULL(nothing,zero,void,nada),那麼方法就沒有辦法執行。 然後運行時通過拋出一個NullPointerException來讓你知道這一點。

你的引用是“指向”空,因此“空 - >指針”。

該對象位於VM內存空間中,訪問它的唯一方法是使用this引用。 以這個例子:

public class Some {
    private int id;
    public int getId(){
        return this.id;
    }
    public setId( int newId ) {
        this.id = newId;
    }
}
....
....
// Somewhere else...
Some reference = new Some();    // Point to a new object of type Some()
Some otherReference = null;     // Initiallly this points to NULL

reference.setId( 1 );           // Execute setId method, now private var id is 1

System.out.println( reference.getId() ); // Prints 1 to the console

otherReference = reference      // Now they both point to the only object.

reference = null;               // "reference" now point to null.

// But "otherReference" still point to the "real" object so this print 1 too...
System.out.println( otherReference.getId() );

// Guess what will happen
System.out.println( reference.getId() ); // :S Throws NullPointerException because "reference" is pointing to NULL remember...

這是一個重要的事情要知道 - 當沒有更多的對象引用(在上面的例子中,當referenceotherReference指向null),那麼對otherReference “不可達”的。 我們無法使用它,因此此對像被標記為垃圾收集,並且在某個時刻,VM將釋放此對象使用的內存並分配另一個內存。


就像你試圖訪問一個null對像一樣。 考慮下面的例子。

TypeA objA;

這時你剛剛聲明了這個對象,但沒有初始化或實例化 。 每當你嘗試訪問其中的任何屬性或方法時,它將拋出NullPointerException ,這是有道理的。

請參閱下面的示例。

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown

已經有很多解釋說明它是如何發生的以及如何解決它,但是您還應該遵循最佳實踐來避免NullPointerException

另請參閱: 最佳實踐的好名單

我會補充一點,非常重要的是,充分利用final修飾語。 在Java中適用時使用“final”修飾符

概要:

  1. 使用final修飾符來強制執行良好的初始化。
  2. 避免在方法中返回null,例如在適用時返回空集合。
  3. 使用註釋@NotNull@Nullable
  4. 快速失敗並使用斷言來避免空對像在整個應用程序中傳播時,它們不應該為空。
  5. 首先使用equals與已知對象: if("knownObject".equals(unknownObject)
  6. 通過toString() valueOf() ()。
  7. 使用null安全的StringUtils方法StringUtils.isEmpty(null)

當應用程序嘗試在需要對象的情況下使用null時,會引發空指針異常。 這些包括:

  1. 調用null對象的實例方法。
  2. 訪問或修改null對象的字段。
  3. null的長度視為數組。
  4. 像訪問數組一樣訪問或修改null的槽。
  5. 如果它是Throwable值,則拋出null

應用程序應該拋出此類的實例來指示其他非法使用null對象。

參考: JavaDocs : JavaDocs


當聲明一個對像數組時,會發生另一個NullPointerException ,然後立即嘗試解除引用其中的元素。

String[] phrases = new String[10];
String keyPhrase = "Bird";
for(String phrase : phrases) {
    System.out.println(phrase.equals(keyPhrase));
}

如果比較順序顛倒,這個特定的NPE可以避免; 即在保證的非空對.equals上使用.equals

數組內的所有元素都被初始化為它們的公共初始值 ; 對於任何類型的對像數組,這意味著所有元素都是null

訪問或取消引用它們之前,必須初始化數組中的元素。

String[] phrases = new String[] {"The bird", "A bird", "My bird", "Bird"};
String keyPhrase = "Bird";
for(String phrase : phrases) {
    System.out.println(phrase.equals(keyPhrase));
}






nullpointerexception