關於java程式異常處理(講義)(轉)

ba發表於2007-08-15
關於java程式異常處理(講義)(轉)[@more@]第16講:異常處理
16.1、簡介:
異常是程式執行時遇到的任何錯誤情況或意外行為。
以下這些情況都可以引發異常:您的程式碼或呼叫的程式碼(如共享庫)中有錯誤,作業系統資源不可用,公共語言執行庫遇到意外情況(如無法驗證程式碼),等等

《Exception Handling for C++》關於異常處理論文,
向物件中每增加一個類,都可能包含一些錯誤。
Java使用和C++類似的異常處理
1、處理錯誤的方法有很多流行方法
2、一般方法是把程式處理程式碼段分散到系統程式碼中,在可能發生錯誤的地方處理錯誤
優點:便於程式設計師能夠條理的看到程式中異常的處理
缺點:異常處理程式“攪亂”程式碼,程式設計師很難關心程式本身能否正常完成功能,而只關心了效能。
3、常見異常例項包括:陣列下標越界,演算法溢位(超出數值表達範圍),除數為零,無效引數、記憶體溢位
異常處理功能:主要處理一些同步異常(除數為0),不宜處理一些非同步事件(Disk I/O End、網路資訊到達、點選滑鼠、敲擊鍵盤)這些最好使用java事件監聽。
異常處理程式:能夠讓系統在出現異常的情況下恢復過來的程式
使用異常處理情況:異常診斷與異常處理不在同一個位置下時使用異常處理程式(若使用者一直透過鍵盤與程式通話,那麼就不能使用處理鍵盤輸入處理)
使用異常的注意事項:
1、 異常處理位置與異常發生位置必須不同(若一個程式能夠處理自己的錯誤,那麼就採用傳統的錯誤處理方式進行區域性處理)
2、 要避免使用異常處理來代替錯誤處理,若這樣就會降低程式的清晰性。
3、 儘管可以使用異常處理來代替錯誤處理,但會降低效能
4、 異常處理會佔用程式的格外執行時間
5、 異常處理能夠提高程式的容錯性
6、 程式設計師使用JAVA標準的異常處理功能來代替他們的專用方法,可以在大型專案中提高程式的清晰性
7、 異常是超類Exception繼承的子類,主要如何處理“未撲獲的異常”,無法預料的異常。
8、 異常處理在java中原理:

異常處理有Method呼叫者的呼叫者或者Method呼叫者來處理,
9、 異常處理適用分別開發的元件系統
10、 因為一些程式設計師使用不支援異常處理語言程式設計時,往往拖延或忘記錯誤處理程式的編寫,故,Java強制程式設計師從專案一開始就著手進行異常處理,程式設計師必須投入很大精力把異常處理的策略融合到軟體產品中
11、 最好在進行系統設計是就把異常處理融合在系統中,若系統一實現,就很難新增異常處理功能

16.2如何使用異常處理:

在以下情況下使用異常處理:

1、 當方法因無法控制的原因而不能實現其功能時;
2、 處理來自程式元件整體異常,這些程式元件不適宜直接處理異常
3、 在大型專案中,對於每個專案都以一致的方式進行錯誤處理
4、 在類庫中出現每一個異常,都需要一個惟一錯誤處理,在類庫中使用異常處理很合適

16.3 其他的錯誤處理技術:

處理異常的方法:
1、 在程式可以忽略異常(忽略異常在大型公用軟體和關鍵處理軟體可能會導致重大的軟體破壞,而自己用的軟體,通常可忽略一些錯誤)
2、 遇到異常時,程式可以根據提示來終止執行(但是處理關鍵任務是絕對不可以採用,〈神5返回倉溫控系統〉?863專案。)

16.4 java異常處理的基礎:

java的異常處理適用於在一個方法中能夠檢測出錯誤單不能處理錯誤的情況,這樣方法將丟擲一個異常(JAVA無法保證“存在”的異常處理程式能夠處理某種異常,若“存在”,就“捕獲”異常,並處理“異常”,如找不到,那麼:

命令列APP/控制檯APP(不基於GUI),當異常不能被“捕獲”,那麼該程式會執行預設異常處理程式,退出JAVA,若Applet或基於GUI的 APP,當一個異常未被“捕獲”,GUI在執行預設異常處理程式依然會顯示,而且使用者使用的GUI處於一個不穩定的狀態)

JAVA程式碼中:1、可能出現異常的程式碼-----{ …… try{丟擲一個異常}-----程式塊 ……catch1{異常處理程式1};……catch100 {異常處理程式100}; finally{無類是否出現異常都執行的程式}
1、 若try丟擲Exception,App尋找在Catch1~100尋找合適異常處理程式,若找到,執行CATCH{}程式碼,沒有,執行最後一個catch{}後程式碼
2、 若try未丟擲Exception,就執行執行最後一個catch{}後程式碼。

3、 throws子句來丟擲指定的異常,異常丟擲點(throws 語句位置、try{}程式塊、try()程式塊中直接和間接呼叫的方法中)

4、 java採用終止方式異常處理,不是恢復方式的異常處理

5、 發生異常時,異常周圍資訊(丟擲物件本身型別)-------------異常處理程式

12.5一個異常處理的簡單例項:除數為0

需求:使用一個小應用程式,完成兩數相除的計算

分析:
我們使用有頂向下,逐步求精的方法:
1、首步我們一般在程式中先處理我們完成異常處理的類,完成異常處理的功能,因為可能除數為0是會出現異常,我們查詢java.lang包中各個 Exception類,發現RuntimeException類集合中的ArithmeticException可以處理運算異常,我們就讓一個 DivideByZeroException(繼承於ArithmeticException)更特殊類來專門處理除數為零的異常。在DivideByZeroException()中呼叫super()(專門初始化傳如引數的方法)來傳如異常處理後物件描述(初始狀態)
2、 第一步,建立一個Applet類完成完成兩數相除的計算
3、 第二步:處理物件與方法:宣告4個GUI元件物件和1個用於儲存計算結果(double)的和2個被除數與除數基本型別(int)

A、 初始化物件方法init()
B、 處理當除數鍵盤輸入後,觸發事件進行計算的方法(返回判斷)action()

a、因為在此方法中,有可能出現除數為0的可能,而且在計算中才回出現錯誤,錯誤出現後需要進行處理異常,那麼我在其中使用try{}程式塊先呼叫方法 quotient進行計算result=quotient(number1,number2),1、然後讓quotient()方法(使用方法體中的 throws Ex{}丟擲異常程式塊---此為深層巢狀)丟擲異常(因為此處理資訊比較簡單,但存在資訊傳遞,我們讓其拖後處理)我們沒有顯式在try()塊中丟擲異常。有丟擲異常就有獲得異常,使用catch{}程式塊完成,a)、在quotient()中(實際深層巢狀throws Ex{}丟擲異常程式塊),當除數=0時,就呼叫throw子句建立並丟擲一個new catch{}“捕獲”(指定匹配型別DivideByZeroException) quotient()丟擲異常資訊(DivideByZeroException),而接受此資訊是由exception接收,並呼叫toString ()方法把exception轉換成字串,使用showStatus(exception.toString()); 顯示出來(因為需求要求顯示異常)。b)、若當除數!=0時,那麼就不丟擲異常,然後將程式返回到try()程式塊中quotient()方法呼叫處,接著使用 showStatus()方法顯示算式和結果(number1+”/”+number2+”=”+Double.toString(result))程式將跳過catch{}程式塊,action()方法將執行return true

注意:當quotient()丟擲異常資訊(DivideByZeroException)時,quotient()終止執行,這樣會對所有物件(4+2 +1)設定標記,用於無用單元回收處理;並在無用單元回收處理之前,還將執行這些物件的終止函式。如果丟擲異常,那麼try在程式塊執行 showStatus之前終止。若try丟擲異常之前自動建立了物件,那麼會對這些物件設定標記,用於無用單元回收,同時在回收之前,還將執行這些物件的終止函式。
b、在action()方法中要注意處理:在TextField中第2個輸入結束並按下回車後,除數應該怎樣獲得輸入的數字(number1= Integer.parseInt(input1.getText)),文字框如何獲得合法的文字(setText()).也包括判斷(if (event.target==input2))

C、 因為quotient()方法任務比較多,所以要將此方法單獨與action來處理,而顯示程式的清晰性和可讀性,同時可以提高執行效率和穩定效能。

類圖與流程圖:

程式碼:
//Fig 16.4: DivideByZeroException.java
//W.Qiang
//2005.J.6
public class DivideByZeroException extends ArithmeticException{
public DivideByZeroException()
{
super(“Attempted to divide by zero”);
}
}
import java.awt.*;
import java.awt.event.*
import java.applet.Applet;

public class DivideByZeroTest extends Applet
{
Label prompt1,prompt2;
TextField input1,input2;
Int number1,number2;
Double result;

public void init()
{
prompt1=new Label (“輸入被除數”);
input1=new TextField(10);
prompt2=new Label (“輸入除數並按下回車”);
input2=new TextField(10);
add (prompt1);
add (input1);
add (prompt2);
add (input2);
}

public boolean action (Event event,Object obeject )
{
if (event.target==input2)
{
number1=Integer.parseInt(input1.getText());
input1.setText(“”);
number2=Integer.parseInt(input2.getText());
input2.setText(“”);

try {
result=quotient(number1,number2);
showStatus(number1+”/”+number2+”=”+Double.toString(result));
}

catch(DivideByZeroException exception) {
showStatus(exception.toString());
}
}
return true;
}
public double quotient(int numerator,int denominator)throws DivideByZeroException
{
if (denominator==0)
throw new DivideByZeroException ();
else (denominator!=0)
return(double) numerator / denominator ;
}
}

12.6 try程式塊:
try{
……}
catch(){
…….}
finally{ ……}
try後面跟0~多個catch程式塊
若try丟擲Exception,App尋找在Catch1~100尋找合適異常處理程式,若找到,執行CATCH{}程式碼,沒有,執行最後一個catch{}後程式碼
若try未丟擲Exception,就執行執行最後一個catch{}後程式碼。
finally{無類是否出現異常都執行的程式,必須完成資源釋放即終止函式呼叫,可避免資源洩露}
16.7 丟擲異常:
throw 子句用來丟擲異常,而throws子句用來指定異常
throw 的運算元是Throwable所有派生類,Throwable的直接子類是Exception(異常,由應捕獲的問題引起,應進行處理)與Error(重大系統問題,一般不捕獲)
丟擲異常丟擲點有try{}塊、, try{}塊某個深層巢狀的作用域、try{}塊某個深層巢狀的方法中,throws指定異常,throw丟擲的異常
try{}不包括錯誤檢測語句與throw子句,但它的程式塊中所引用的物件將會執行建構函式中的錯誤檢測程式碼,並丟擲異常
我們只要求異常終止產生異常的程式塊執行,而不停止整個程式
異常資訊傳遞透過物件引用產生,然後讓catch塊中的引數名(物件名)引用
16.8 捕獲異常:

異常處理程式包含在catch程式塊中
語法:
catch (classNmae---指定要丟擲的異常的型別,引數名-----用來引用處理程式捕獲的物件){javaCode -----處理異常可執行程式碼}

catch使用注意事項:
1、 若假設異常處理之後,程式控制將返回throw後的第一個語句,那麼將導致邏輯錯誤
2、 將catch程式塊的引數不能設定成多個,一個catch只有一個引數
3、 若兩個catch程式塊(均和某個try程式塊有關)都用於捕獲同一型別異常,那麼將產生語法錯誤
4、 捕獲特殊異常可能找不到,需要在下一層try中找,若找不到,那麼命令列APP/控制檯APP(不基於GUI)將退出程式,Applet或基於GUI的APP將繼續執行處於一個不穩定的狀態的APP
5、 若某一型別異常,可能有幾個異常處理程式與他相匹配,那麼執行first相匹配的異常處理程式
6、一個程式可以同時處理許多關係密切的異常,我們可謂此ExceptionGroup提供1個異常類與catch處理程式,當某個異常發生時,可根據不同的例項資料建立異常物件,同時catch檢查該資料,以判斷異常的型別;我們一般不提倡此種程式設計風格,最好用繼承的方法解決
7、 在異常處理程式中,不能訪問try塊中定義的物件,異常處理開始,try快結束
8、 若執行某個異常處理程式時又丟擲一個異常,原try塊已經終止,那麼就讓原try外層try處理程式進行處理,同時外層try程式監視並處理原try塊的catch處理程式產生的錯誤
9、異常處理程式的形式:A、重丟擲異常;B、透過丟擲另一種不同型別的異常來轉換異常型別;C、透過執行完最後一個異常處理程式之後,完成任何必要的恢復工作並使程式繼續執行;D、判斷產生錯誤的原因,然後處理,並重新呼叫原來曾產生該異常的方法 E、簡單向Runtime返回一個狀態值 ……………等等
10、 傳統的控制流不使用異常,因“額外的”異常會“掩蓋”那些真正的錯誤型別的異常,程式設計師很難跟蹤那些大量的異常,而且這裡的異常不是經常見到的
11、 catch處理程式丟擲一個異常,將由catch處理或與同1個try塊相關的其他處理程式來處理,就會產生邏輯錯誤

16.9 重丟擲異常:
catch異常處理程式中出現異常,需要其他catch處理程式處理該異常
可以用throw重丟擲異常

16.10 throws 子句:

用途:在一個method中,利用其列出該方法所能丟擲的異常
int g (float h) throws a,b,c
{
//method body
}
丟擲的物件為:指定類物件或者子類物件

1、執行時異常:發生異常是某些可避免的事情出現錯誤
此異常是RuntimeException類派生出來的
包括:ArrayIndexOutOfBoundsException(訪問一個越界陣列下標),NullPointerException(Null引用操作丟擲---宣告而沒有建立物件);
ClassCastException (無效的型別轉換引發)
IOException ,InterruptedException

Throws不必要顯式指出RuntimeException與Error,而要指出method或該method所呼叫的method顯式丟擲非RuntimeException異常
3、 java異常區分:經檢查的Exception(非RuntimeException);未經檢查的Exception(RuntimeException);Error

注意事項:
1、 method丟擲一個經檢查的Exception,若該Exception未列在throws子句中,會產生語法錯誤
2、 試圖在一個沒有throws子句中method丟擲異常,會產生語法錯誤
3、 若method1呼叫method2(顯示丟擲經檢查的Exception),必須在method1的子句列出此異常,除非method2已經捕獲此異常
4、 子類method的throws清單是父類method的throws清單的子集
5、 捕獲異常必須處理,才能滿足“java捕獲或宣告”。
6、 java編譯器強制程式設計師處理異常,絕對不能忽略異常處理
7、 java列出的Error見j2SDK 1.42 Documention 的java.lang package errors (AWTError)
8、 java列出的Exception見j2SDK 1.42 Documention 的java.lang package Exception 、 java.util package Exception 、java.io package Exception、java.awt package Exception、java.net package Exception

16.11建構函式、終止函式和異常處理

當建構函式檢測錯誤(不能返回值)解決方案(讓程式知道無法正確構造該物件):
1、直接返回該錯誤物件,當使用該物件進行判斷,以確定此物件是否錯誤
2、在該建構函式外設定一個全域性變數,都不是好方法3、丟擲異常,把次函式錯誤資訊傳遞到外部,並處理該錯誤
4、 當該函式丟擲Exception ,那麼該函式建立的物件將被設定標記,用與最終的無用單元回收處理,故需要呼叫終止函式。

16.12異常與繼承:

因為繼承關係,各種錯誤可以多型處理
一般最好捕獲並處理父類異常,(僅當所有子類物件的處理方法都一致才有意義),否則,捕獲子類異常

16.13 finally程式塊

若程式顯示使用某些資源,那麼必須在最後完成對資源的釋放即無庸單元回收,在C與C++中,常見是指標不能回收,函式不能終止,出現“記憶體洩露”
java實現自動的無庸的單元回收功能,可避免“記憶體洩露”,但java同樣存在別的“資源洩露”
一般在finally程式塊中使用一些資源釋放的程式碼
1、 finally程式塊將try程式塊中所有開啟檔案關閉
2、 java並沒有徹底消除資源洩露、當某個物件不存在是,java才對該物件進行無庸單元回收處理,當程式設計師錯誤的對某個物件保持引用時,就會出現記憶體洩露
3、 exception ( String informationString):其中informationString是對該類異常描述資訊,而獲得資訊使用getMessage(用於返回儲存在某個異常中的描述字串)。PrintStackTrace(用於把方法呼叫堆疊的內容列印出來,對測試程式特別有用)。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10617731/viewspace-958167/,如需轉載,請註明出處,否則將追究法律責任。

相關文章