如何診斷 Java 中的 Null 異常訊息
1. 概述
Java中的異常可以幫助我們發現並修復錯誤。但是,當異常訊息為null
時會發生什麼,讓我們絞盡腦汁尋找線索呢?
在這個快速教程中,讓我們研究一下這個問題。
2.問題介紹
像往常一樣,讓我們透過一個例子來理解這個問題:
class Team {
private String name;
//... getters and setters
}
class Player {
private static Logger LOG = LoggerFactory.getLogger(Player.class);
private String name;
private Team team;
public Player(String name) {
this.name = name;
}
void output() {
try {
if (team != null) {
LOG.info("Player:{}, Team:{}", name.toUpperCase(), team.getName().toUpperCase());
} else {
throw new IllegalArgumentException("Team is null");
}
} catch (Exception e) {
LOG.error("Error occurred:" + e.getMessage());
}
}
//... getters and setters
}
如上面的程式碼所示,我們有一個Player
引用Team
實例.
在output()
方法中,當目前Player
的team
為null
時,我們會拋出IllegalArgumentException
並包含有意義的訊息。此外,整個output()
主體被包裝在一個try-catch
區塊中。
接下來,讓我們建立一個Player
實例來呼叫output()
:
Player kai = new Player("Kai");
kai.setTeam(new Team());
kai.output();
如範例所示,我們在建立 kai 後呼叫了kai.output()
。
如果我們使用 JDK 14 之前的 JDK 運行此程式碼,我們將看到以下輸出:
10:03:54.016 [main] ERROR com.baeldung...Player -- Error occurred: null
null
異常訊息令人困惑,對於發現問題所在沒有幫助。
接下來,讓我們了解為什麼會發生這種情況以及如何避免混淆null
訊息。
3. 了解null
異常訊息表示什麼
通常,當我們在 Java 中看到null
異常訊息時,通常表示異常是在沒有訊息的情況下拋出的。例如,當應用程式使用早於 JDK14 的 JDK 運行時,就會引發NullPointerException()
。
如果我們仔細查看程式碼, Player
實例 ( kai
) 確實有一個非空Team
引用。但是,我們尚未設定Team.name
屬性。也就是說, team.getName()
為null
。因此, team.getName().toUpperCase()
會拋出意外的NullPointerException
。
在 JDK14 之前, **NullPointerException**
沒有訊息,因此輸出顯示null
訊息。
JEP 358已在 JDK14 中實現。因此,從JDK14開始, NullPointerException
有一個詳細的訊息來指示是什麼導致了異常。例如,如果我們使用 JDk17 運行相同的程式碼,輸出如下所示:
10:23:53.016 [main] ERROR com.baeldung...Player -- Oops! Error occurred.Cannot invoke "String.toUpperCase()" because the return value of "com.baeldung...Team.getName()" is null
這次,該訊息指出了導致NullPointerException
的原因,這有助於引導我們找到根本原因並修復錯誤。
然而,有時,我們必須使用較舊的 JDK。那麼,接下來,讓我們看看如何避免混淆null
異常訊息。
4.堆疊追蹤而不是訊息
當我們遇到異常並想要找到其根本原因時,堆疊追蹤是我們的起點。因此,當我們輸出異常時,我們應該包含它的堆疊追蹤。
取得堆疊追蹤的常見方法是呼叫Exception.printStackTrace()
方法:
void outputWithStackTrace() {
try {
// ... same code
} catch (Exception e) {
e.printStackTrace();
}
}
我們僅將catch
區塊中的LOG.error()
呼叫替換為e.printStackTrace()
.
現在,如果我們建立相同的Player kai
並且呼叫kai.outputWithStackTrace()
,我們會得到以下輸出:
java.lang.NullPointerException
at com.baeldung...Player.outputWithStackTrace(ExceptionGetMessageNullUnitTest.java:48)
...
即使沒有訊息,堆疊追蹤也會告訴我們遇到了NullPointerException
以及發生異常的確切程式碼行。這給了我們一個焦點。
有時,我們仍然想使用記錄器來管理應用程式錯誤訊息。例如,我們在範例中使用 SLF4J。因此,我們可以使用SLF4J來記錄異常:
void outputWithStackTraceLog() {
try {
// ... same code
} catch (Exception e) {
LOG.error("Error occurred.", e);
}
}
現在,如果我們呼叫kai.outputWithStackTraceLog()
,我們會得到錯誤日誌:
10:36:31.961 [main] ERROR com.baeldung...Player -- Error occurred.
java.lang.NullPointerException
at com.baeldung...Player.outputWithStackTraceLog(ExceptionGetMessageNullUnitTest.java:60)
...
如輸出所示,此錯誤日誌有助於我們尋找並修復「 Team.name
is null”
問題。
5. 結論
在本文中,我們討論了為什麼可能會收到null
異常訊息,並探討如何取得異常的堆疊追蹤以幫助定位根本原因。
與往常一樣,完整的源代碼可以 在 GitHub 上取得。