熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java核心技術 >> 正文

Java異常處理原理及應用

2013-11-23 18:41:51  來源: Java核心技術 

  readLine 方法有時產生 IOException如何處理潛在的故障?編譯器需要捕獲聲明IOException

  捕獲 (catch)指當 readLine 方法產生錯誤時截獲該錯誤並處理和記錄該問題聲明 (declare)指錯誤可能引發 IOException並通知調用該方法的任何代碼可能產生異常

  若要捕獲異常必須添加一個特殊的處理代碼塊來接收和處理 IOException於是程序改為如下

  import javaio*; public class EchoInputHandle { public static void main(String args[]){ Systemoutprintln(Enter text to echo:); InputStreamReader isr = new InputStreamReader(Systemin); BufferedReader inputReader = new BufferedReader(isr); try{ String inputLine = inputReaderreadLine(); Systemoutprintln(Read: + inputLine); } catch(IOException exc){ Systemoutprintln(Exception encountered: + exc); } } } 新添的代碼塊包含關鍵字 try 和 catch(第 行)表示要讀取輸入若成功則正常運行若讀取輸入時錯誤則捕獲問題(由 IOException 對象表示)並采取相應措施在本例采用的處理方式是輸出異常

  若不准備捕獲 IOException僅聲明異常則要特別指定 main 方法可能出錯而且特別說明可能產生 IOException於是程序改為如下

  import javaio*; public class EchoInputDeclare { public static void main(String args[]) throws IOException{ Systemoutprintln(Enter text to echo:); InputStreamReader isr = new InputStreamReader(Systemin); BufferedReader inputReader = new BufferedReader(isr); String inputLine = inputReaderreadLine(); Systemoutprintln(Read: + inputLine); } } 從上面的這個簡單的例子中我們可以看出異常處理在 Java 代碼開發中不能被忽視

  Java 異常以及異常處理

  可將 Java 異常看作是一類消息它傳送一些系統問題故障及未按規定執行的動作的相關信息異常包含信息以將信息從應用程序的一部分發送到另一部分

  編譯語言為何要處理異常?為何不在異常出現位置隨時處理具體故障?因為有時候我們需要在系統中交流錯誤消息以便按照統一的方式處理問題有時是因為有若干處理問題的可能方式但您不知道使用哪一種此時可將處理異常的任務委托給調用方法的代碼調用者通常更能了解問題來源的上下文能更好的確定恢復方式

  必定在運行的 Java 應用程序的一些類或對象中產生異常出現故障時發送者將產生異常對象異常可能代表 Java 代碼出現的問題也可能是 JVM 的相應錯誤或基礎硬件或操作系統的錯誤

  異常本身表示消息指發送者傳給接收者的數據負荷首先異常基於類的類型來傳輸有用信息很多情況下基於異常的類既能識別故障本因並能更正問題其次異常還帶有可能有用的數據(如屬性)

  在處理異常時消息必須有接收者否則將無法處理產生異常的底層問題

  在上例中異常產生者是讀取文本行的 BufferedReader在故障出現時將在 readLine 方法中構建 IOException 對象異常接收者是代碼本身EchoInputHandle 應用程序的 trycatch 結構中的 catch 塊是異常的接收者它以字符串形式輸出異常將問題記錄下來

  Java 異常類的層次結構

  在我們從總體上了解異常後我們應該了解如何在 Java 應用程序中使用異常即需要了解 Java 類的層次結構

  必定在運行的 Java 應用程序的一些類或對象中產生異常出現故障時發送者將產生異常對象異常可能代表 Java 代碼出現的問題也可能是 JVM 的相應錯誤或基礎硬件或操作系統的錯誤

  異常本身表示消息指發送者傳給接收者的數據負荷首先異常基於類的類型來傳輸有用信息很多情況下基於異常的類既能識別故障本因並能更正問題其次異常還帶有可能有用的數據(如屬性)

  在處理異常時消息必須有接收者否則將無法處理產生異常的底層問題

  在上例中異常產生者是讀取文本行的 BufferedReader在故障出現時將在 readLine 方法中構建 IOException 對象異常接收者是代碼本身EchoInputHandle 應用程序的 trycatch 結構中的 catch 塊是異常的接收者它以字符串形式輸出異常將問題記錄下來

  Java 異常類的層次結構

  在我們從總體上了解異常後我們應該了解如何在 Java 應用程序中使用異常即需要了解 Java 類的層次結構

  必定在運行的 Java 應用程序的一些類或對象中產生異常出現故障時發送者將產生異常對象異常可能代表 Java 代碼出現的問題也可能是 JVM 的相應錯誤或基礎硬件或操作系統的錯誤

  異常本身表示消息指發送者傳給接收者的數據負荷首先異常基於類的類型來傳輸有用信息很多情況下基於異常的類既能識別故障本因並能更正問題其次異常還帶有可能有用的數據(如屬性)

  在處理異常時消息必須有接收者否則將無法處理產生異常的底層問題

  在上例中異常產生者是讀取文本行的 BufferedReader在故障出現時將在 readLine 方法中構建 IOException 對象異常接收者是代碼本身EchoInputHandle 應用程序的 trycatch 結構中的 catch 塊是異常的接收者它以字符串形式輸出異常將問題記錄下來

  Java 異常類的層次結構

  在我們從總體上了解異常後我們應該了解如何在 Java 應用程序中使用異常即需要了解 Java 類的層次結構

  在 Java 中所有的異常都有一個共同的祖先 Throwable(可拋出)Throwable 指定代碼中可用異常傳播機制通過 Java 應用程序傳輸的任何問題的共性

  Throwable 有兩個重要的子類Exception(異常)和 Error(錯誤)二者都是 Java 異常處理的重要子類各自都包含大量子類

  Exception(異常)是應用程序中可能的可預測可恢復問題一般大多數異常表示中度到輕度的問題異常一般是在特定環境下產生的通常出現在代碼的特定方法和操作中在 EchoInput 類中當試圖調用 readLine 方法時可能出現 IOException 異常

  Error(錯誤)表示運行應用程序中較嚴重問題大多數錯誤與代碼編寫者執行的操作無關而表示代碼運行時 JVM(Java 虛擬機)出現的問題例如當 JVM 不再有繼續執行操作所需的內存資源時將出現 OutOfMemoryError

  Exception 類有一個重要的子類 RuntimeExceptionRuntimeException 類及其子類表示JVM 常用操作引發的錯誤例如若試圖使用空值對象引用除數為零或數組越界則分別引發運行時異常(NullPointerExceptionArithmeticException)和 ArrayIndexOutOfBoundException

  Java 異常的處理

  在 Java 應用程序中對異常的處理有兩種方式處理異常和聲明異常

  處理異常trycatch 和 finally

  若要捕獲異常則必須在代碼中添加異常處理器塊這種 Java 結構可能包含 個部分

  都有 Java 關鍵字下面的例子中使用了 trycatchfinally 代碼結構

  import javaio*; public class EchoInputTryCatchFinally { public static void main(String args[]){ Systemoutprintln(Enter text to echo:); InputStreamReader isr = new InputStreamReader(Systemin); BufferedReader inputReader = new BufferedReader(isr); try{ String inputLine = inputReaderreadLine(); Systemoutprintln(Read: + inputLine); } catch(IOException exc){ Systemoutprintln(Exception encountered: + exc); } finally{ Systemoutprintln(End ); } } 其中

  try 塊將一個或者多個語句放入 try 時則表示這些語句可能拋出異常編譯器知道可能要發生異常於是用一個特殊結構評估塊內所有語句

  catch 塊當問題出現時一種選擇是定義代碼塊來處理問題catch 塊的目的便在於此catch 塊是 try 塊所產生異常的接收者基本原理是一旦生成異常則 try 塊的執行中止JVM 將查找相應的 JVM

  finally 塊還可以定義 finally 塊無論運行 try 塊代碼的結果如何該塊裡面的代碼一定運行在常見的所有環境中finally 塊都將運行無論 try 塊是否運行完無論是否產生異常也無論是否在 catch 塊中得到處理finally 塊都將執行

  trycatchfinally 規則

  必須在 try 之後添加 catch 或 finally 塊try 塊後可同時接 catch 和 finally 塊但至少有一個塊

  必須遵循塊順序若代碼同時使用 catch 和 finally 塊則必須將 catch 塊放在 try 塊之後

  catch 塊與相應的異常類的類型相關

  一個 try 塊可能有多個 catch 塊若如此則執行第一個匹配塊

  可嵌套 trycatchfinally 結構

  在 trycatchfinally 結構中可重新拋出異常

  除了下列情況總將執行 finally 做為結束JVM 過早終止(調用 Systemexit(int))在 finally 塊中拋出一個未處理的異常計算機斷電失火或遭遇病毒攻擊

  聲明異常

  若要聲明異常則必須將其添加到方法簽名塊的結束位置下面是一個實例

  public void errorProneMethod(int input) throws javaioIOException { //Code for the methodincluding one or more method //calls that may produce an IOException } 這樣聲明的異常將傳給方法調用者而且也通知了編譯器該方法的任何調用者必須遵守處理或聲明規則聲明異常的規則如下

  必須聲明方法可拋出的任何可檢測異常(checked exception)

  非檢測性異常(unchecked exception)不是必須的可聲明也可不聲明

  調用方法必須遵循任何可檢測異常的處理和聲明規則若覆蓋一個方法則不能聲明與覆蓋方法不同的異常聲明的任何異常必須是被覆蓋方法所聲明異常的同類或子類

  Java 異常處理的分類

  Java 異常可分為可檢測異常非檢測異常和自定義異常

  可檢測異常

  可檢測異常經編譯器驗證對於聲明拋出異常的任何方法編譯器將強制執行處理或聲明規則例如sqlExecption 這個異常就是一個檢測異常你連接 JDBC 時不捕捉這個異常編譯器就通不過不允許編譯

  非檢測異常

  非檢測異常不遵循處理或聲明規則在產生此類異常時不一定非要采取任何適當操作編譯器不會檢查是否已解決了這樣一個異常例如一個數組為 個長度當你使用下標為3時就會產生數組下標越界異常這個異常 JVM 不會進行檢測要靠程序員來判斷有兩個主要類定義非檢測異常RuntimeException 和 Error

  Error 子類屬於非檢測異常因為無法預知它們的產生時間若 Java 應用程序內存不足則隨時可能出現 OutOfMemoryError起因一般不是應用程序的特殊調用而是 JVM 自身的問題另外Error 一般表示應用程序無法解決的嚴重問題

  RuntimeException 類也屬於非檢測異常因為普通 JVM 操作引發的運行時異常隨時可能發生此類異常一般是由特定操作引發但這些操作在 Java 應用程序中會頻繁出現因此它們不受編譯器檢查與處理或聲明規則的限制

  自定義異常

  自定義異常是為了表示應用程序的一些錯誤類型為代碼可能發生的一個或多個問題提供新含義可以顯示代碼多個位置之間的錯誤的相似性也可以區分代碼運行時可能出現的相似問題的一個或者多個錯誤或給出應用程序中一組錯誤的特定含義例如對隊列進行操作時有可能出現兩種情況空隊列時試圖刪除一個元素滿隊列時試圖添加一個元素則需要自定義兩個異常來處理這兩種情況

  Java 異常處理的原則和忌諱

  Java 異常處理的原則

  盡可能的處理異常

  要盡可能的處理異常如果條件確實不允許無法在自己的代碼中完成處理就考慮聲明異常如果人為避免在代碼中處理異常僅作聲明則是一種錯誤和依賴的實踐

  具體問題具體解決

  異常的部分優點在於能為不同類型的問題提供不同的處理操作有效異常處理的關鍵是識別特定故障場景並開發解決此場景的特定相應行為為了充分利用異常處理能力需要為特定類型的問題構建特定的處理器塊

  記錄可能影響應用程序運行的異常

  至少要采取一些永久的方式記錄下可能影響應用程序操作的異常理想情況下當然是在第一時間解決引發異常的基本問題不過無論采用哪種處理操作一般總應記錄下潛在的關鍵問題別看這個操作很簡單但它可以幫助您用很少的時間來跟蹤應用程序中復雜問題的起因

  根據情形將異常轉化為業務上下文

  若要通知一個應用程序特有的問題有必要將應用程序轉換為不同形式若用業務特定狀態表示異常則代碼更易維護從某種意義上講無論何時將異常傳到不同上下文(即另一技術層)都應將異常轉換為對新上下文有意義的形式

  Java 異常處理的忌諱

  一般不要忽略異常

  在異常處理塊中一項最危險的舉動是不加通告地處理異常如下例所示

  try{ ClassforName(businessdomainCustomer); } catch (ClassNotFoundException exc){} 經常能夠在代碼塊中看到類似的代碼塊有人總喜歡在編寫代碼時簡單快速地編寫空處理器塊自我安慰地宣稱准備在後期添加恢復代碼但這個後期變成了無期

  這種做法有什麼壞處?如果異常對應用程序的其他部分確實沒有任何負面影響這未嘗不可但事實往往並非如此異常會擾亂應用程序的狀態此時這樣的代碼無異於掩耳盜鈴

  這種做法若影響較輕則應用程序可能出現怪異行為例如應用程序設置的一個值不見了 或 GUI 失效若問題嚴重則應用程序可能會出現重大問題因為異常未記錄原始故障點難以處理如重復的 NullPointerExceptions

  如果采取措施記錄了捕獲的異常則不可能遇到這個問題實際上除非確認異常對代碼其余部分絕無影響至少也要作記錄進一步講永遠不要忽略問題否則風險很大在後期會引發難以預料的後果

  不要使用覆蓋式異常處理塊

  另一個危險的處理是覆蓋式處理器(blanket handler)該代碼的基本結構如下

  try{ // … } catch(Exception e){ // … } 使用覆蓋式異常處理塊有兩個前提之一

   代碼中只有一類問題

  這可能正確但即便如此也不應使用覆蓋式異常處理捕獲更具體的異常形式有利物弊

   單個恢復操作始終適用

  這幾乎絕對錯誤幾乎沒有哪個方法能放之四海而皆准能應對出現的任何問題

  分析下這樣編寫代碼將發生的情況只要方法不斷拋出預期的異常集則一切正常但是如果拋出了未預料到的異常則無法看到要采取的操作當覆蓋式處理器對新異常類執行千篇一律的任務時只能間接看到異常的處理結果如果代碼沒有打印或記錄語句則根本看不到結果

  更糟糕的是當代碼發生變化時覆蓋式處理器將繼續作用於所有新異常類型並以相同方式處理所有類型

  一般不要把特定的異常轉化為更通用的異常

  將特定的異常轉換為更通用異常時一種錯誤做法一般而言這將取消異常起初拋出時產生的上下文在將異常傳到系統的其他位置時將更難處理見下例

  try{ // Errorprone code } catch(IOException e){ String msg = If you didn t have a problem beforeyou do now!; throw new Exception(msg); } 因為沒有原始異常的信息所以處理器塊無法確定問題的起因也不知道如何更正問題

  不要處理能夠避免的異常

  對於有些異常類型實際上根本不必處理通常運行時異常屬於此類范疇在處理空指針或者數據索引等問題時不必求助於異常處理

  Java 異常處理的應用實例

  在定義銀行類時若取錢數大於余額時需要做異常處理

  定義一個異常類 insufficientFundsException取錢(withdrawal)方法中可能產生異常條件是余額小於取額

  處理異常在調用 withdrawal 的時候因此 withdrawal 方法要聲明拋出異常由上一級方法調用

  異常類

  class InsufficientFundsExceptionextends Exception{ private Bank excepbank; // 銀行對象 private double excepAmount; // 要取的錢 InsufficientFundsException(Bank ba double dAmount) { excepbank=ba; excepAmount=dAmount; } public String excepMessage(){ String str=The balance is+excepbankbalance + \n+The withdrawal was+excepAmount; return str; } }// 異常類 銀行類

  class Bank{ double balance;// 存款數 Bank(double balance){thisbalance=balance;} public void deposite(double dAmount){ if(dAmount>) balance+=dAmount; } public void withdrawal(double dAmount) throws InsufficientFundsException{ if (balance<dAmount) throw new InsufficientFundsException(this dAmount); balancebalance=balancedAmount; } public void showBalance(){ Systemoutprintln(The balance is +(int)balance); } } 前端調用

  public class ExceptionDemo{ public static void main(String args[]){ try{ Bank ba=new Bank(); bawithdrawal(); Systemoutprintln(Withdrawal successful!); }catch(InsufficientFundsException e) { Systemoutprintln(etoString()); Systemoutprintln(eexcepMessage()); } } } 總結

  Java 異常處理是使用 Java 語言進行軟件開發和測試腳本開發中非常重要的一個方面對異常處理的重視會是您開發出的代碼更健壯更穩定本文系統的闡述了 Java 異常處理的原理和方法能幫助讀者更加清楚的理解 Java 異常處理機制在開發代碼時更加靈活的使用它


From:http://tw.wingwit.com/Article/program/Java/hx/201311/25596.html
  • 上一篇文章:

  • 下一篇文章:
  • 推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.