Java中的空指針異常怎么避免?
Java中如何避免空指針異常,這也是由初級程序員成長到中級程序員的時候經常會遇到的問題。
程序員不知道或不信任正在使用的約定,并且小心的檢查著null。還有當程序員寫代碼的時候,總是會依賴于通過返回空(NULL)來表明某些意義,因此需要調用者去檢查Null。
有兩種空指針的檢查場景:
期望的結果就是null。
期望的結果不是null。
第二種很簡單,可以通過用assert或者允許程序報錯,例如拋出NullPointerException。Assertions是一個從Java1.4加進來的高度未被利用的特性,語法是:
assert <condition>
或者
assert <condition> : <object>
condition是一個布爾表達式,object是一個對象(其toString()方法的輸出將會被包含在錯誤里)。
校對注:我測試了下,JDK1.4及其以上,運行前設置vm參數-ea
public static void main(String[] args) {
String name = null;
assert (name != null) : "name為空null";
}
Exception in thread "main";
java.lang.AssertionError: 變量name為空nullat LogUtil.main(LogUtil.java:37)
如果condition為false的話,assert將會拋出一個Error(AssertionError)。默認Java會忽略斷言你可以通過在JVM中傳入一個-ea參數來啟用斷言。
你可以為單獨的一個包或者類啟動關閉assertions。這意味著你可以在開發(fā)和測試的時候通過斷言來驗證代碼,在發(fā)布產品的時候關閉它,盡管我下面展示的測試中并沒有因為assertions而損失性能。在這個代碼段中不用斷言也可以,因為他會運行失敗的,就像加了斷言一樣。唯一的區(qū)別是有了斷言可能會發(fā)生的更快一些,更有意義,并且會附加一些額外的信息,而這可以幫助你弄明白失敗的原因。
第一種有一點棘手。如果你對不能控制正在調用的這段代碼,那你就卡住了。如果Null是一個合理的返回值,你就應該檢查它。如果是你能夠控制的代碼,那就是個完全不同的故事情景了。盡量避免用NULL作為返回值。對于返回Collections的集合很容易,返回Empty(一個空集合或者數組),而不是一直用null作為返回值。對于不是返回Collections的方法會有一點復雜。考慮下面這個例子:
public interface Action {
void doSomething();
}
public interface Parser {
Action findAction(String userInput);
}
Parser采用用戶的輸入作為參數,然后做一些事情(例如模擬一個命令行)。現在你可能會返回null,如果沒找到對應輸入的動作的話,這就導致了剛才說過的空指針檢查。
一個可選的解決方案是永遠不要返回null,而是返回一個空對象
public class MyParser implements Parser { private static Action DO_NOTHING = new Action() { public void doSomething() { /* do nothing */ }
}; public Action findAction(String userInput) { // ...
if ( /* we can't find any actions */ ) {
return DO_NOTHING;
}
}}
比較這段代碼:
Parser parser = ParserFactory.getParser();if (parser == null) {
// now what?
// this would be an example of where null isn't (or shouldn't be) a valid response}Action action = parser.findAction(someInput);if (action == null) {
// do nothing} else {
action.doSomething();}
和這段:
ParserFactory.getParser().findAction(someInput).doSomething();
這是個更好的設計,因為足夠簡潔,避免了多余的判斷。
即便如此,或許比較合適的設計是:findAction()方法之惡杰拋出一個異常,其中包含一些有意義的錯誤信息—–特別是在這個案例中你依賴于用戶的輸入。
讓findAction()方法拋出一個異常而不是簡單的產生一個沒有任何解釋的NullPointerException 要好得多。
try {
ParserFactory.getParser().findAction(someInput).doSomething();} catch(ActionNotFoundException anfe) {
userConsole.err(anfe.getMessage());}
或者你認為try/catch 的機制太丑了,你的action應該跟用戶提供一個反饋而不是什么都不做:
public Action findAction(final String userInput) { /* Code to return requested Action if found */
return new Action() {
public void doSomething() {
userConsole.err("Action not found: " + userInput);
}
}}
作者:碼出宇宙
歡迎關注微信公眾號 :碼出宇宙
掃描添加好友邀你進技術交流群,加我時注明【姓名+公司(學校)+職位】