亚洲精品中文字幕无乱码_久久亚洲精品无码AV大片_最新国产免费Av网址_国产精品3级片

java語言

Java的異常處理及應(yīng)用

時(shí)間:2024-10-01 18:38:25 java語言 我要投稿
  • 相關(guān)推薦

Java的異常處理及應(yīng)用

  Java 異常處理是使用Java 語言進(jìn)行軟件開發(fā)和測試腳本開發(fā)時(shí)不容忽視的問題之一,是否進(jìn)行異常處理直接關(guān)系到開發(fā)出的軟件的穩(wěn)定性和健壯性。本文系統(tǒng)的闡述了 Java 異常處理的原理和方法,并列舉了一些實(shí)例,使讀者對 Java 異常處理能有一個(gè)全面的認(rèn)識,理解異常處理機(jī)制,能更加靈活和有效地在開發(fā)中使用它。下面是小編為大家?guī)淼年P(guān)于Java的異常處理及應(yīng)用的知識,歡迎閱讀。

  Java 異常處理引出

  假設(shè)您要編寫一個(gè) Java 程序,該程序讀入用戶輸入的一行文本,并在終端顯示該文本。

  程序如下:

  1 import java.io.*;

  2 public class EchoInput {

  3 public static void main(String args[]){

  4 System.out.println("Enter text to echo:");

  5 InputStreamReader isr = new InputStreamReader(System.in);

  6 BufferedReader inputReader = new BufferedReader(isr);

  7 String inputLine = inputReader.readLine();

  8 System.out.println("Read:" + inputLine);

  9 }

  10 }

  分析上面的代碼,在 EchoInput 類中,第 3 行聲明了 main 方法;第 4 行提示用戶輸入文本;第 5、6 行設(shè)置 BufferedReader 對像連接到 InputStreamReader,而 InputStreamReader 又連接到標(biāo)準(zhǔn)輸入流 System.in;第 7 行讀入一行文本;第 8 行用標(biāo)準(zhǔn)輸出流 System.out 顯示出該文本。

  表面看來上面的程序沒有問題,但實(shí)際上,EchoInput 類完全可能出現(xiàn)問題。要在調(diào)用第 7 行的 readLine 方法時(shí)正確讀取輸入,這幾種假設(shè)都必須成立:假定鍵盤有效,鍵盤能與計(jì)算機(jī)正常通信;假定鍵盤數(shù)據(jù)可從操作系統(tǒng)傳輸?shù)?Java 虛擬機(jī),又從 Java 虛擬機(jī)傳輸 inputReader。

  大多數(shù)情況下上述假設(shè)都成立,但不盡然。為此,Java 采用異常方法,以應(yīng)對可能出現(xiàn)的錯(cuò)誤,并采取步驟進(jìn)行更正。在本例中,若試圖編譯以上代碼,將看到以下信息:

  Exception in thread "main" java.lang.Error: Unresolved compilation problem:

  Unhandled exception type IOException

  at EchoInput.main(EchoInput.java:7)

  從中可以看到,第 7 行調(diào)用 readLine 方法可能出錯(cuò):若果真如此,則產(chǎn)生 IOException 來記錄故障。編譯器錯(cuò)誤是在告訴您,需要更改代碼來解決這個(gè)潛在的問題。在 JDK API 文檔中,可以看到同樣的信息。我們可以看到 readLine 方法,如圖 1 所示。

  “捕獲 (catch)”指當(dāng) readLine 方法產(chǎn)生錯(cuò)誤時(shí)截獲該錯(cuò)誤,并處理和記錄該問題。而“聲明 (declare)”指錯(cuò)誤可能引發(fā) IOException,并通知調(diào)用該方法的任何代碼:可能產(chǎn)生異常。

  若要捕獲異常,必須添加一個(gè)特殊的“處理代碼塊”,來接收和處理 IOException。于是程序改為如下:

  1 import java.io.*;

  2 public class EchoInputHandle {

  3 public static void main(String args[]){

  4 System.out.println("Enter text to echo:");

  5 InputStreamReader isr = new InputStreamReader(System.in);

  6 BufferedReader inputReader = new BufferedReader(isr);

  7 try{

  8 String inputLine = inputReader.readLine();

  9 System.out.println("Read:" + inputLine);

  10 }

  11 catch(IOException exc){

  12 System.out.println(“Exception encountered: ” + exc);

  13 }

  14 }

  15 }

  新添的代碼塊包含關(guān)鍵字 try 和 catch(第 7,10,11,13 行),表示要讀取輸入。若成功,則正常運(yùn)行。若讀取輸入時(shí)錯(cuò)誤,則捕獲問題(由 IOException 對象表示),并采取相應(yīng)措施。在本例,采用的處理方式是輸出異常。

  若不準(zhǔn)備捕獲 IOException,僅聲明異常,則要特別指定 main 方法可能出錯(cuò),而且特別說明可能產(chǎn)生 IOException。于是程序改為如下:

  1 import java.io.*;

  2 public class EchoInputDeclare {

  3 public static void main(String args[]) throws IOException{

  4 System.out.println("Enter text to echo:");

  5 InputStreamReader isr = new InputStreamReader(System.in);

  6 BufferedReader inputReader = new BufferedReader(isr);

  7 String inputLine = inputReader.readLine();

  8 System.out.println("Read:" + inputLine);

  9 }

  10 }

  從上面的這個(gè)簡單的例子中,我們可以看出異常處理在 Java 代碼開發(fā)中不能被忽視。

  Java 異常以及異常處理

  可將 Java 異常看作是一類消息,它傳送一些系統(tǒng)問題、故障及未按規(guī)定執(zhí)行的動(dòng)作的相關(guān)信息。異常包含信息,以將信息從應(yīng)用程序的一部分發(fā)送到另一部分。

  編譯語言為何要處理異常?為何不在異常出現(xiàn)位置隨時(shí)處理具體故障?因?yàn)橛袝r(shí)候我們需要在系統(tǒng)中交流錯(cuò)誤消息,以便按照統(tǒng)一的方式處理問題,有時(shí)是因?yàn)橛腥舾商幚韱栴}的可能方式,但您不知道使用哪一種,此時(shí),可將處理異常的任務(wù)委托給調(diào)用方法的代碼。調(diào)用者通常更能了解問題來源的上下文,能更好的確定恢復(fù)方式。

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

  在處理異常時(shí),消息必須有接收者;否則將無法處理產(chǎn)生異常的底層問題。

  在上例中,異!爱a(chǎn)生者”是讀取文本行的 BufferedReader。在故障出現(xiàn)時(shí),將在 readLine 方法中構(gòu)建 IOException 對象。異!敖邮照摺笔谴a本身。EchoInputHandle 應(yīng)用程序的 try-catch 結(jié)構(gòu)中的 catch 塊是異常的接收者,它以字符串形式輸出異常,將問題記錄下來。

  Java 異常類的層次結(jié)構(gòu)

  在我們從總體上了解異常后,我們應(yīng)該了解如何在 Java 應(yīng)用程序中使用異常,即需要了解 Java 類的層次結(jié)構(gòu)。

  在 Java 中,所有的異常都有一個(gè)共同的祖先 Throwable(可拋出)。Throwable 指定代碼中可用異常傳播機(jī)制通過 Java 應(yīng)用程序傳輸?shù)娜魏螁栴}的共性。

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

  Exception(異常)是應(yīng)用程序中可能的可預(yù)測、可恢復(fù)問題。一般大多數(shù)異常表示中度到輕度的問題。異常一般是在特定環(huán)境下產(chǎn)生的,通常出現(xiàn)在代碼的特定方法和操作中。在 EchoInput 類中,當(dāng)試圖調(diào)用 readLine 方法時(shí),可能出現(xiàn) IOException 異常。

  Error(錯(cuò)誤)表示運(yùn)行應(yīng)用程序中較嚴(yán)重問題。大多數(shù)錯(cuò)誤與代碼編寫者執(zhí)行的操作無關(guān),而表示代碼運(yùn)行時(shí) JVM(Java 虛擬機(jī))出現(xiàn)的問題。例如,當(dāng) JVM 不再有繼續(xù)執(zhí)行操作所需的內(nèi)存資源時(shí),將出現(xiàn) OutOfMemoryError。

  Exception 類有一個(gè)重要的子類 RuntimeException。RuntimeException 類及其子類表示“JVM 常用操作”引發(fā)的錯(cuò)誤。例如,若試圖使用空值對象引用、除數(shù)為零或數(shù)組越界,則分別引發(fā)運(yùn)行時(shí)異常(NullPointerException、ArithmeticException)和 ArrayIndexOutOfBoundException。

  Java 異常的處理

  在 Java 應(yīng)用程序中,對異常的處理有兩種方式:處理異常和聲明異常。

  處理異常:try、catch 和 finally

  若要捕獲異常,則必須在代碼中添加異常處理器塊。這種 Java 結(jié)構(gòu)可能包含 3 個(gè)部分,

  都有 Java 關(guān)鍵字。下面的例子中使用了 try-catch-finally 代碼結(jié)構(gòu)。

  1 import java.io.*;

  2 public class EchoInputTryCatchFinally {

  3 public static void main(String args[]){

  4 System.out.println("Enter text to echo:");

  5 InputStreamReader isr = new InputStreamReader(System.in);

  6 BufferedReader inputReader = new BufferedReader(isr);

  7 try{

  8 String inputLine = inputReader.readLine();

  9 System.out.println("Read:" + inputLine);

  10 }

  11 catch(IOException exc){

  12 System.out.println("Exception encountered: " + exc);

  13 }

  14 finally{

  15 System.out.println("End. ");

  16 }

  17 }

  18}

  其中:

  try 塊:將一個(gè)或者多個(gè)語句放入 try 時(shí),則表示這些語句可能拋出異常。編譯器知道可能要發(fā)生異常,于是用一個(gè)特殊結(jié)構(gòu)評估塊內(nèi)所有語句。

  catch 塊:當(dāng)問題出現(xiàn)時(shí),一種選擇是定義代碼塊來處理問題,catch 塊的目的便在于此。catch 塊是 try 塊所產(chǎn)生異常的接收者;驹硎牵阂坏┥僧惓#瑒t try 塊的執(zhí)行中止,JVM 將查找相應(yīng)的 JVM。

  finally 塊:還可以定義 finally 塊,無論運(yùn)行 try 塊代碼的結(jié)果如何,該塊里面的代碼一定運(yùn)行。在常見的所有環(huán)境中,finally 塊都將運(yùn)行。無論 try 塊是否運(yùn)行完,無論是否產(chǎn)生異常,也無論是否在 catch 塊中得到處理,finally 塊都將執(zhí)行。

  try-catch-finally 規(guī)則:

  必須在 try 之后添加 catch 或 finally 塊。try 塊后可同時(shí)接 catch 和 finally 塊,但至少有一個(gè)塊。

  必須遵循塊順序:若代碼同時(shí)使用 catch 和 finally 塊,則必須將 catch 塊放在 try 塊之后。

  catch 塊與相應(yīng)的異常類的類型相關(guān)。

  一個(gè) try 塊可能有多個(gè) catch 塊。若如此,則執(zhí)行第一個(gè)匹配塊。

  可嵌套 try-catch-finally 結(jié)構(gòu)。

  在 try-catch-finally 結(jié)構(gòu)中,可重新拋出異常。

  除了下列情況,總將執(zhí)行 finally 做為結(jié)束:JVM 過早終止(調(diào)用 System.exit(int));在 finally 塊中拋出一個(gè)未處理的異常;計(jì)算機(jī)斷電、失火、或遭遇病毒攻擊。

  聲明異常

  若要聲明異常,則必須將其添加到方法簽名塊的結(jié)束位置。下面是一個(gè)實(shí)例:

  public void errorProneMethod(int input) throws java.io.IOException {

  //Code for the method,including one or more method

  //calls that may produce an IOException

  }

  這樣,聲明的異常將傳給方法調(diào)用者,而且也通知了編譯器:該方法的任何調(diào)用者必須遵守處理或聲明規(guī)則。聲明異常的規(guī)則如下:

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

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

  調(diào)用方法必須遵循任何可檢測異常的處理和聲明規(guī)則。若覆蓋一個(gè)方法,則不能聲明與覆蓋方法不同的異常。聲明的任何異常必須是被覆蓋方法所聲明異常的同類或子類。

  Java 異常處理的分類

  Java 異?煞譃榭蓹z測異常,非檢測異常和自定義異常。

  可檢測異常

  可檢測異常經(jīng)編譯器驗(yàn)證,對于聲明拋出異常的任何方法,編譯器將強(qiáng)制執(zhí)行處理或聲明規(guī)則,例如:sqlExecption 這個(gè)異常就是一個(gè)檢測異常。你連接 JDBC 時(shí),不捕捉這個(gè)異常,編譯器就通不過,不允許編譯。

  非檢測異常

  非檢測異常不遵循處理或聲明規(guī)則。在產(chǎn)生此類異常時(shí),不一定非要采取任何適當(dāng)操作,編譯器不會檢查是否已解決了這樣一個(gè)異常。例如:一個(gè)數(shù)組為 3 個(gè)長度,當(dāng)你使用下標(biāo)為3時(shí),就會產(chǎn)生數(shù)組下標(biāo)越界異常。這個(gè)異常 JVM 不會進(jìn)行檢測,要靠程序員來判斷。有兩個(gè)主要類定義非檢測異常:RuntimeException 和 Error。

  Error 子類屬于非檢測異常,因?yàn)闊o法預(yù)知它們的產(chǎn)生時(shí)間。若 Java 應(yīng)用程序內(nèi)存不足,則隨時(shí)可能出現(xiàn) OutOfMemoryError;起因一般不是應(yīng)用程序的特殊調(diào)用,而是 JVM 自身的問題。另外,Error 一般表示應(yīng)用程序無法解決的嚴(yán)重問題。

  RuntimeException 類也屬于非檢測異常,因?yàn)槠胀?JVM 操作引發(fā)的運(yùn)行時(shí)異常隨時(shí)可能發(fā)生,此類異常一般是由特定操作引發(fā)。但這些操作在 Java 應(yīng)用程序中會頻繁出現(xiàn)。因此,它們不受編譯器檢查與處理或聲明規(guī)則的限制。

  自定義異常

  自定義異常是為了表示應(yīng)用程序的一些錯(cuò)誤類型,為代碼可能發(fā)生的一個(gè)或多個(gè)問題提供新含義?梢燥@示代碼多個(gè)位置之間的錯(cuò)誤的相似性,也可以區(qū)分代碼運(yùn)行時(shí)可能出現(xiàn)的相似問題的一個(gè)或者多個(gè)錯(cuò)誤,或給出應(yīng)用程序中一組錯(cuò)誤的特定含義。例如,對隊(duì)列進(jìn)行操作時(shí),有可能出現(xiàn)兩種情況:空隊(duì)列時(shí)試圖刪除一個(gè)元素;滿隊(duì)列時(shí)試圖添加一個(gè)元素。則需要自定義兩個(gè)異常來處理這兩種情況。

  Java 異常處理的原則和忌諱

  Java 異常處理的原則

  盡可能的處理異常

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

  具體問題具體解決

  異常的部分優(yōu)點(diǎn)在于能為不同類型的問題提供不同的處理操作。有效異常處理的關(guān)鍵是識別特定故障場景,并開發(fā)解決此場景的特定相應(yīng)行為。為了充分利用異常處理能力,需要為特定類型的問題構(gòu)建特定的處理器塊。

  記錄可能影響應(yīng)用程序運(yùn)行的異常

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

  根據(jù)情形將異常轉(zhuǎn)化為業(yè)務(wù)上下文

  若要通知一個(gè)應(yīng)用程序特有的問題,有必要將應(yīng)用程序轉(zhuǎn)換為不同形式。若用業(yè)務(wù)特定狀態(tài)表示異常,則代碼更易維護(hù)。從某種意義上講,無論何時(shí)將異常傳到不同上下文(即另一技術(shù)層),都應(yīng)將異常轉(zhuǎn)換為對新上下文有意義的形式。

  Java 異常處理的忌諱

  一般不要忽略異常

  在異常處理塊中,一項(xiàng)最危險(xiǎn)的舉動(dòng)是“不加通告”地處理異常。如下例所示:

  1 try{

  2 Class.forName("business.domain.Customer");

  3 }

  4 catch (ClassNotFoundException exc){}

  經(jīng)常能夠在代碼塊中看到類似的代碼塊。有人總喜歡在編寫代碼時(shí)簡單快速地編寫空處理器塊,并“自我安慰地”宣稱準(zhǔn)備在“后期”添加恢復(fù)代碼,但這個(gè)“后期”變成了“無期”。

  這種做法有什么壞處?如果異常對應(yīng)用程序的其他部分確實(shí)沒有任何負(fù)面影響,這未嘗不可。但事實(shí)往往并非如此,異常會擾亂應(yīng)用程序的狀態(tài)。此時(shí),這樣的代碼無異于掩耳盜鈴。

  這種做法若影響較輕,則應(yīng)用程序可能出現(xiàn)怪異行為。例如,應(yīng)用程序設(shè)置的一個(gè)值不見了, 或 GUI 失效。若問題嚴(yán)重,則應(yīng)用程序可能會出現(xiàn)重大問題,因?yàn)楫惓N从涗浽脊收宵c(diǎn),難以處理,如重復(fù)的 NullPointerExceptions。

  如果采取措施,記錄了捕獲的異常,則不可能遇到這個(gè)問題。實(shí)際上,除非確認(rèn)異常對代碼其余部分絕無影響,至少也要作記錄。進(jìn)一步講,永遠(yuǎn)不要忽略問題;否則,風(fēng)險(xiǎn)很大,在后期會引發(fā)難以預(yù)料的后果。

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

  另一個(gè)危險(xiǎn)的處理是覆蓋式處理器(blanket handler)。該代碼的基本結(jié)構(gòu)如下:

  1 try{

  2 // …

  3 }

  4 catch(Exception e){

  5 // …

  6 }

  使用覆蓋式異常處理塊有兩個(gè)前提之一:

  1. 代碼中只有一類問題。

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

  2. 單個(gè)恢復(fù)操作始終適用。

  這幾乎絕對錯(cuò)誤。幾乎沒有哪個(gè)方法能放之四海而皆準(zhǔn),能應(yīng)對出現(xiàn)的任何問題。

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

  更糟糕的是,當(dāng)代碼發(fā)生變化時(shí),覆蓋式處理器將繼續(xù)作用于所有新異常類型,并以相同方式處理所有類型。

  一般不要把特定的異常轉(zhuǎn)化為更通用的異常

  將特定的異常轉(zhuǎn)換為更通用異常時(shí)一種錯(cuò)誤做法。一般而言,這將取消異常起初拋出時(shí)產(chǎn)生的上下文,在將異常傳到系統(tǒng)的其他位置時(shí),將更難處理。見下例:

  1 try{

  2 // Error-prone code

  3 }

  4 catch(IOException e){

  5 String msg = "If you didn ’ t have a problem before,you do now!";

  6 throw new Exception(msg);

  7 }

  因?yàn)闆]有原始異常的信息,所以處理器塊無法確定問題的起因,也不知道如何更正問題。

  不要處理能夠避免的異常

  對于有些異常類型,實(shí)際上根本不必處理。通常運(yùn)行時(shí)異常屬于此類范疇。在處理空指針或者數(shù)據(jù)索引等問題時(shí),不必求助于異常處理。

  Java 異常處理的應(yīng)用實(shí)例

  在定義銀行類時(shí),若取錢數(shù)大于余額時(shí)需要做異常處理。

  定義一個(gè)異常類 insufficientFundsException。取錢(withdrawal)方法中可能產(chǎn)生異常,條件是余額小于取額。

  處理異常在調(diào)用 withdrawal 的時(shí)候,因此 withdrawal 方法要聲明拋出異常,由上一級方法調(diào)用。

  異常類:

  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"+excepbank.balance

  + " "+"The withdrawal was"+excepAmount;

  return str;

  }

  }// 異常類

  銀行類:

  class Bank{

  double balance;// 存款數(shù)

  Bank(double balance){this.balance=balance;}

  public void deposite(double dAmount){

  if(dAmount>0.0) balance+=dAmount;

  }

  public void withdrawal(double dAmount)

  throws InsufficientFundsException{

  if (balance

  InsufficientFundsException(this, dAmount);

  balance=balance-dAmount;

  }

  public void showBalance(){

  System.out.println("The balance is "+(int)balance);

  }

  }

  前端調(diào)用:

  public class ExceptionDemo{

  public static void main(String args[]){

  try{

  Bank ba=new Bank(50);

  ba.withdrawal(100);

  System.out.println("Withdrawal successful!");

  }catch(InsufficientFundsException e) {

  System.out.println(e.toString());

  System.out.println(e.excepMessage());

  }

  }

  }


【Java的異常處理及應(yīng)用】相關(guān)文章:

Java異常處理語句及解析07-27

Java的異常機(jī)制分析及處理辦法10-27

Java編程中異常處理的方法10-02

全面理解java中的異常處理機(jī)制精選08-11

java運(yùn)行異常的示例10-31

java運(yùn)行異常示例09-09

java運(yùn)行異常分析08-04

java封裝產(chǎn)品異常的代碼08-02

如何處理PHP異常10-30

java的應(yīng)用范圍06-24