編程中的異常表示程序執行過程中某個時刻的異常情況。當異常情況可以在其他地方更好地處理而不是在遇到異常情況的地方處理時,可以使用它。考慮以下示例:
在所有這些情況下(以及更多情況下),應該在生成異常的位置之外處理異常,以便可以解決根本原因。
下圖顯示了Java異常層次結構的主要部分。基類是可丟棄的,它被分為異常和錯誤。類異常適用於程序相關的條件,應用程序可以捕獲這些條件以試圖挽救這種情況。另一方面,類錯誤用於指示Java運行時環境中應用程序不應捕獲的嚴重錯誤。例如:OutOfMemoryError和StackOverflowerError。
異常有兩種類型:checked和unchecked。已檢查的異常必須由調用代碼處理。此規則由java編譯器強制執行。另一方面,未經檢查的異常可以向上傳播到調用鏈,而不必顯式聲明它。下面的例子將闡明。
以下方法嘗試從文件創建FileReader。構造函數拋出一個選中的異常FileNotFoundException,該異常必須由調用代碼處理或聲明為拋出。
以下代碼將不會編譯,因為它既不編譯也不編譯。
private void loadFile(String filename){ FileReader in = new FileReader(filename);}獲取要編譯的代碼的一種方法是處理異常(見下文)。
private void loadFile(String filename){ try { FileReader in = new FileReader(filename)); { } catch(FileNotFoundException ex) { // handle exception here }}如果調用方無法直接處理異常,則必須在方法簽名中聲明該異常。
private void loadFile(String filename) throws java.io.FileNotFoundException{ FileReader in = new FileReader(filename)); {}未檢查的異常是從RuntimeException子類化的異常,不需要像上面那樣直接處理或聲明。例如,下面的代碼會導致NullPointerException,這是RuntimeException的一種類型。但是,由於NullPointerException是未檢查的異常,因此代碼編譯時不會出錯。
private void handleEvent(){ String name = null; if ( name.length() > 0 ) { }}鑑於上面關於檢查和未檢查異常的討論,處理未檢查異常似乎更容易,因為您不必自己聲明或處理它們。考慮到這種方便性,有時將選中的異常包裝到未選中的異常中可能很有用。
下面的代碼示例演示瞭如何包裝異常。方法\u 1()在其主體中拋出一個SQLException。要使代碼正確編譯,必須聲明拋出異常。
private void method_1() throws SQLException { ... throw new SQLException;}當從另一個方法(method_2())調用此方法時,該方法可以捕獲SQLException並將其包裝在未檢查的異常中,因此它不必在其方法簽名中聲明異常。
private void method_2() { try { method_1(); } catch(java.sql.SQLException ex) { throw new RuntimeException(ex); }}異常堆棧跟蹤指的是活動堆棧幀的數組,每個幀表示在拋出異常時由JVM捕獲的方法調用。每個堆棧幀包括方法調用的位置,包括類名、方法名,可能還有java源文件名和文件中的行號。它有助於追溯導致錯誤的調用序列。
下面是一個典型的堆棧跟蹤,從捕獲異常對象時獲取。
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 8, Size: 5 at java.util.ArrayList.rangeCheck(ArrayList.java:653) at java.util.ArrayList.get(ArrayList.java:429) at sample.sample1.main(sample1.java:24)這裡捕獲的異常是IndexOutOfBoundsException。它包括有關錯誤的附加信息。堆棧跟蹤包含3個堆棧幀,每個幀都包含位置信息,如圖所示。
可以通過在try-catch塊中捕獲異常並採取所需的任何糾正措施來處理異常。Exception對象提供了幾種方法來提取有關導致異常的條件的信息。
下面的代碼將錯誤消息記錄到日誌文件中。
private void loadConfig() { try { // invoke code which might generate an IOException } catch(java.io.IOException ex) { // handle exception here. May be log to a log file. log.warning(ex.getMessage()); }}將異常包裝到另一個異常中時,可以檢索包裝的異常:
Throwable cause = ex.getCause();log.warning("Underlying cause: " + cause.getMessage());是否需要訪問堆棧跟蹤,或者提取導致堆棧跟蹤的方法的名稱?
StringBuilder **uf = new StringBuilder("Stack Trace: ");for (StackTraceElement el : ex.getStackTrace()) { **uf.append(el.getClassName() + "." + el.getMethodName()).append("");}log.warning(**uf.toString());或者,記錄異常並重試它?
try { ...} catch(java.io.IOException ex) { log.warning(ex.getMessage()); throw ex;}Exception類提供了一個printStackTrace()方法,可以將堆棧跟蹤打印到您自己的PrintStream(或PrintWriter)中。
try { ...} catch(java.io.IOException ex) { PrintStream out = ...; out.println(ex.getMessage()); ex.printStackTrace(out);}您可以在一個try塊中捕獲多種類型的異常,並對每種類型的異常執行特定的處理。
try { // throws some excepti*** here} catch(java.io.IOException ex) { // IOException specific handling here} catch(java.sql.SQLException ex) { // SQLException specific handling here}要捕獲多個異常類型但使用相同的處理代碼,可以按如下方式聲明具有多個類型的catch塊:
try { // throws some excepti*** here} catch(java.io.IOException | java.sql.SQLException ex) { // IOException and SQLException specific handling here} catch(SAXException ex) { // SAXException specific handling here}在處理可能引發異常的代碼時,必須對任何資源(如打開的文件、數據庫連接等)執行適當的清理。資源清理應在finally塊中執行。這樣,塊的正常退出和異常退出都會調用清除代碼。
InputStream in = null;try { ... in = new FileInputStream(filename); ...} catch(java.io.IOException ex) { log.warning(ex.getMessage());} finally { // code here is executed on exiting the try block, // whether normally or due to an exception if ( in != null ) in.close();}Java1.7引入了try-with-resources結構,使資源清理更容易。看起來是這樣的:
try( InputStream in = new FileInputStream(..) ) { // code which uses the InputStream.}當代碼退出塊時(無論是乾淨的還是由於異常),InputStream變量將自動清除。
通過在塊頭中聲明所有資源來清理多個資源。
try( InputStream in = new FileInputStream(..); Connection con = ...; ) { // code which uses the InputStream and the Connection.}任何類實現AutoCloseable接口的對象都可以用這種方式清除。下面的類在close()方法中執行一些特定的清理。
public class MyClass implements AutoCloseable { public void close() { // cleanup code here }}在try with resources塊中使用此類的實例。
try( MyClass obj = new MyClass(..) ) { // code which uses the MyClass object.}現在讓我們來看看一些常見的異常。
異常是Java中錯誤報告和管理的主要方法。正確使用異常可以提高代碼質量並幫助解決生產中的問題。
你有什麼與戰爭故事有關的例外嗎?如果是,請在下面的評論部分告訴我們。
圖片來源:Dmitry Nikolaev viaShutterstock.com網站
...常見的執行時錯誤是被零除並計算超出陣列邊界的元素。異常是由程式中的執行時錯誤引起的條件。當發生異常時,程式執行終止。如果程式設計師想繼續執行剩餘的程式碼,那麼程式設計師可以捕獲由錯誤條件引發的異常物件...
...別——java中的休眠與等待 Sleep和wait是Java中用於多執行緒處理的兩種方法。sleep方法屬於Thread類,而wait方法來自Object類。Java中sleep和wait的關鍵區別在於,sleep用於在指定的毫秒數內暫停當前執行緒的執行,而wait方法用於使當前...
關鍵區別——java中的檢查異常與未檢查異常 異常是執行時錯誤。有兩種型別的異常稱為檢查異常和未檢查異常。當發生選中的異常時,Java應用程式連線到外部資源,如檔案、裝置或資料庫。這些異常由編譯器檢查。檢查的...
...防止更改變數、避免方法重寫和避免擴充套件類。最後是異常處理中的一個塊,無論是否引發異常,它都將執行。finalize是一個方法,由垃圾回收器在完全銷燬物件之前呼叫。這就是Java中final和finalize的關鍵區別。 目錄 1. 概述和...
... 程式碼可能丟擲異常,因此如果您打算處理它(例如格式化GUI的錯誤訊息),就可以捕獲它。 ...
...。Java虛擬機器不是自己重寫和重新編譯程式碼,而是為您處理程式碼。 ...
...開發。您還應該熟悉核心Java概念,例如如何在Java中使用異常。你也可以用Java玩得很開心---用Java和處理技術創造出驚人的網路攝像頭效果! ...
...。該方法還需要宣告一個throws子句列表java.rmi.RemoteException異常除了任何特定於應用程式的例外。這使得客戶機程式碼可以處理(或傳播)遠端方法呼叫錯誤,例如找不到主機、連線失敗等。 ...
...謝你自己的。 企業系統—具有高容量資料處理的行業(如銀行業、金融交易等)傾向於將Java用於非遺留系統,因為它快速、可移植、易於維護,並且不太容易出現低階語言中常見的災難性錯誤。 嵌...