【Java基礎】異常
Java中什麼是Exception?
所有的異常都是通過Throwable衍生出來的。Throwable把錯誤進 一步劃分為 java.lang.Exception 和 java.lang.Error. java.lang.Error 用來處理系統錯誤,例如java.lang.StackOverFlowError 或者 Java.lang.OutOfMemoryError 之類的。然後 Exception用來處理程式錯誤,請求的資源不可用等等。
Java中的檢查型異常和非檢查型異常有什麼區別?
這又是一個非常流行的Java異常面試題,會出現在各種層次的Java面試中。檢查型異常和非檢查型異常的主要區別在於其處理方式。檢查型異常需要使用 try, catch和finally關鍵字在編譯期進行處理,否則會出現編譯器會報錯。對於非檢查型異常則不需要這樣做。Java中所有繼承自 java.lang.Exception類的異常都是檢查型異常,所有繼承自RuntimeException的異常都被稱為非檢查型異常。
在Java異常處理的過程中,你遵循的那些最好的實踐是什麼?
這個問題在面試技術經理是非常常見的一個問題。因為異常處理在專案設計中是非常關鍵的,所以精通異常處理是十分必要的。異常處理有很多最佳實踐,下面列舉集中,它們提高你程式碼的健壯性和靈活性:
1) 呼叫方法的時候返回布林值來代替返回null
這樣可以 避免發生NullPointerException。由於空指標是java異常裡最噁心的異常,你可以參考一下下面的技術文章 coding best practices to minimize NullPointerException
2) catch塊裡別不寫程式碼。
空catch塊是異常處理裡的錯誤事件,因為它只是捕獲了異常,卻沒有任何處理或者提示。通常你起碼要打印出異常資訊,當然你最好根據需求對異常資訊進行處理。
3)優先選擇非檢查型異常。
通過去掉重複的異常處理程式碼,可以提高程式碼的可讀性。(boilerplate是樣板檔案的意思,可理解為是拷貝重複之一)
請找到合適的理由
4) 絕對不要讓你的資料庫相關異常顯示到客戶端。
由於絕大多數資料庫和SQLException異常都是檢查型異常,應該在應用的dao層處理這些異常,返回一些值,或者返回有意義的執行時(非檢查型)異常,像這樣客戶端才能理解,並採取一些措施。
5) 在Java中,一定要在資料庫連線,資料庫查詢,流處理後,在finally塊中呼叫close()方法。
我已經在我的文章Top 10 Java exception handling best practices中分享了關於這方面的很多知識,你們也可以看看這篇文章。
既然我們可以用RuntimeException來處理錯誤,那麼你認為為什麼Java中還存在檢查型異常?
- 這是一個有爭議的問題
- 存在 檢查型異常是一個設計上的決定,受到了諸如C++等比Java更早的程式語言設計經驗的影響。絕大多數檢查型異常位於java.io包內,這是合乎情理 的,因為在你請求了不存在的系統資源的時候,一段強壯的程式必須能夠優雅的處理這種情況。通過把IOException宣告為檢查型異常,Java 確保了你能夠優雅的對異常進行處理。(資源緊張一般涉及到IO異常比較多)
- 可以使用catch或finally來確保數量受限的系統資源(比如檔案描述符)在你使用後儘早 得到釋放。 Joshua Bloch編寫的 Effective Java 一書 中多處涉及到了該話題,值得一讀。
什麼是“異常鏈”?
“異常鏈”是Java中非常流行的異常處理概念,是指在進行一個異常處理時丟擲了另外一個異常,由此產生了一個異常鏈條。該技術大多用於將“ 受檢查異常” ( checked exception)封裝成為“非受檢查異常”(unchecked exception)或者RuntimeException。順便說一下,如果因為因為異常你決定丟擲一個新的異常,你一定要包含原有的異常,這樣,處理 程式才可以通過getCause()和initCause()方法來訪問異常最終的根源。
你曾經自定義實現過異常嗎?怎麼寫的?
很顯然,我們絕大多數都寫過自定義或者業務異常,像AccountNotFoundException。在面試過程中詢問這個Java異常問題的主要原因 是去發現你如何使用這個特性的。這可以更準確和精緻的去處理異常,當然這也跟你選擇checked 還是unchecked exception息息相關。通過為每一個特定的情況建立一個特定的異常,你就為呼叫者更好的處理異常提供了更好的選擇。相比通用異常(general exception),我更傾向更為精確的異常。大量的建立自定義異常會增加專案class的個數,因此,在自定義異常和通用異常之間維持一個平衡是成功 的關鍵。
你遇到過 OutOfMemoryError 錯誤嘛?你是怎麼搞定的?
這個面試題會在面試高階程式設計師的時候用,面試官想知道你是怎麼處理這個危險的OutOfMemoryError錯誤 的。必須承認的是,不管你做什麼專案,你都會碰到這個問題。所以你要是說沒遇到過,面試官肯定不會買賬。要是你對這個問題不熟悉,甚至就是沒碰到過,而你 又有3、4年的Java經驗了,那麼準備好處理這個問題吧。在回答這個問題的同時,你也可以藉機向面試秀一下你處理記憶體洩露、調優和除錯方面的牛逼技能。 我發現掌握這些技術的人都能給面試官留下深刻的印象。你們也可以到 how to fix java.lang.OutOfMemoryError去看看我寫的另一篇關於這個問題更詳細細節的文章
如果執行finally程式碼塊之前方法返回了結果,或者JVM退出了,finally塊中的程式碼還會執行嗎?
只有在try裡面是有 System.exit(0)來退出JVM的情況下finally塊中的程式碼才不會執行。
Java中final,finalize,finally關鍵字的區別
這是一個經典的Java面試題了。我的一個朋友為Morgan Stanley招電信方面的核心Java開發人員的時候就問過這個問題。final和finally是Java的關鍵字,而finalize則是方法。 final關鍵字在建立不可變的類的時候非常有用,只是宣告這個類是final的。而finalize()方法則是垃圾回收器在回收一個物件前呼叫,但也 Java規範裡面沒有保證這個方法一定會被呼叫。finally關鍵字是唯一一個和這篇文章討論到的異常處理相關的關鍵字。在你的產品程式碼中,在關閉連線 和資原始檔的是時候都必須要用到finally塊。更多看here
下面的程式碼都有哪些錯誤:
public class SuperClass {
public void start() throws IOException{
throw new IOException("Not able to open file");
}
}
public class SubClass extends SuperClass{
public void start() throws Exception{
throw new Exception("Not able to start");
}
}
這段程式碼編譯器將對子類覆蓋start方法產生不滿。因為每個Java中方法的覆蓋是有規則的,一個覆蓋的方法不能丟擲的異常比原方法繼承關係高。因為這 裡的start方法在超類中丟擲了IOException,所有在子類中的start方法只能丟擲要麼是IOExcepition或是其子類,但不能是其 超類,如Exception。