




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
第6章異常處理6.1程序錯誤與處理6.2Java的異常處理6.3自定義異常類6.4編程實例 6.1程序錯誤與處理程序中的錯誤有不同的性質,不同的錯誤需要采用不同的處理方式。按照錯誤的性質可將程序錯誤分成3類:語法錯、語義錯、邏輯錯。6.1.1程序錯誤、發現時刻及錯誤處理原則1.語法錯違反語法規范的錯誤稱為語法錯,這類錯誤通常在編譯時發現,又稱為編譯錯。Java編譯器能夠發現所有語法錯,給出錯誤的位置和性質。程序員必須及時改正語法錯,再重新編譯程序。2.語義錯如果程序在語法上正確,但在語義上存在錯誤,則稱為語義錯,如除數為0錯、給變量賦予超出其范圍的值、待打開的文件不存在等。語義錯不能被編譯系統發現,只能到程序運行時才能被系統發現,因而又稱為運行錯。在運行時,一旦發現了語義錯,Java將停止程序運行,并給出錯誤的位置和性質。有些語義能夠被程序事先處理,程序中應該設法避免產生這些錯誤;還有一些語義錯不能被程序事先處理,這些錯誤的發生不由程序本身所控制,因此必須進行異常處理。3.邏輯錯如果程序通過編譯,可運行,但運行結果與期望值不符,則這類錯誤稱為邏輯錯。由于系統無法找到邏輯錯,所以邏輯錯最難確定和排除。此時,程序員必須憑借自身的程序設計經驗,找到錯誤原因及出錯位置,從而改正錯誤。6.1.2面向過程語言與面向對象語言的錯誤處理方式比較
面向過程語言——程序運行效率更重要語言本身防范錯誤的責任推給了程序員,使程序質量完全依賴于程序員。程序員必須考慮并防范所有錯誤,為每一個應用程序設置語言一級的錯誤處理機制,這對程序員的要求太高。再者,含有錯誤處理的程序代碼臃腫,邏輯復雜,可讀性差,軟件無法維護和升級。在程序開發過程中,程序員能夠發現并改正語法錯和邏輯錯,但無法防范所有運行時錯誤,這些錯誤的出現不是由程序控制的,面向過程語言沒有提供對這些錯誤的防范和處理機制,只能任憑錯誤的產生而導致程序運行中斷。
6.1.2面向過程語言與面向對象語言的錯誤處理方式比較面向對象語言——程序的正確性、可靠性和穩定性更重要提供語言級的錯誤防范和處理機制,即異常處理機制。異常處理是捕獲和處理運行時錯誤的一種機制。異常處理機制使程序具有處理錯誤的能力,即使發生了運行時錯誤,應用程序能夠捕獲異常并及時處理異常,使程序從運行時錯誤中很好地恢復并繼續運行,而不會導致程序運行非正常終止。異常處理是一種對異常進行事后處理的機制。異常處理機制將運行時錯誤封裝成若干錯誤類和異常類,并提供異常處理語句用于在程序中實現對運行時錯誤的發現和及時處理。6.1.3Java的錯誤和異常一、錯誤與異常根據錯誤的性質,Java將運行時錯誤分為兩類:錯誤和異常。(1)錯誤(error)錯誤指程序運行時遇到的硬件或操作系統的錯誤,如內存溢出、虛擬機錯誤等。錯誤對于程序而言是致命的,錯誤將導致程序無法運行,而且程序本身不能處理錯誤,只能依靠外界干預,否則會一直處于非正常狀態。(2)異常(exception)異常指在硬件和操作系統正常時,程序遇到的運行錯,如操作數超出數據范圍,文件不存在等。異常對于程序而言是非致命性的,雖然異常會導致程序非正常終止,但Java的異常處理機制使程序自身能夠捕獲和處理異常,由異常代碼調整程序運行方向,但程序仍可繼續運行。圖6.1Java程序發現錯誤和異常二、錯誤類和異常類Java中的所有的錯誤類和異常類都是從Throwable類派生出來的。Throwable是異常類的根節點,定義在java.lang包,它的子類也定義在該包中。Throwable類有兩個直接子類:java.lang.Error和java.lang.Exception。Error代表系統錯誤類,由系統直接處理;Exception類及其子類是在程序中可捕捉到的異常。圖6.2錯誤類和異常類的層次結構(1)Error類Error類是錯誤類,Error類對象由Java虛擬機生成并拋出給系統,有內存溢出錯誤、棧溢出錯誤、動態鏈接錯誤等。例如,當運行沒有main()方法的類時,則產生類定義未找到錯誤(NoClassDefFoundError)。(2)Exception類Exception類是異常類,Exception類對象是Java程序捕獲和處理的對象。每一種異常對應Exception類的一個子類,異常對象中包含錯誤的位置和特征信息。每個異常類反映一類運行時錯誤,類定義包含了該類異常的信息和對異常進行處理的方法。Java預定了多種通用的異常類,如除數為0的算術異常、數組下標越界異常、空指針異常等,程序中也可以自定義異常類。每當程序運行過程中發生了某個異常現象,系統將產生一個相應的異常類對象,并交由系統中的相應機制進行處理,以避免死機、死循環或其他對系統不利的結果發生,保證了程序運行的安全性。三、Error錯誤類的子類
Error類及其子類主要用來描述一些Java運行時的系統內部錯誤或資源枯竭導致的錯誤。普通的程序不能從這類錯誤中恢復,也無法拋出這種類型的錯誤,這類錯誤出現的幾率是很小的。
(1)VirtualMachineError虛擬機錯誤OutOfMemoryError內存溢出錯誤StackOverflowError棧溢出錯誤(2)LinkageError鏈接錯誤(3)java.awt.AWTError圖形界面錯誤
Throwable類的一個異常類分支是Exception類和它的子類。在編程中,對異常的處理主要是對這類異常的處理。類Exception是普通程序可以從中恢復的所有標準異常的超類。
Exception類又有兩個分支:從RuntimeException中派生出來的類和從Non-RuntimeException類中派生的類,這樣分類的根據是錯誤發生的原因。
四、Exception異常類的子類(1)RuntimeException運行時異常類,是程序員編寫程序不正確所導致的異常,理論上,程序員經過檢查和測試可以查出這類錯誤。該異常可能出現在程序的任何地方,而且出現的可能性非常大,如果由程序本身去檢測運行異常出現與否,將會使程序的負荷過大,因而編譯器并不要求程序去說明或捕獲運行時異常。(2)Non-RuntimeException非運行時異常類,是由于一些異常的情況造成的,不是程序本身的錯誤,可以由編譯器在編譯時檢測到的、可能會發生在方法執行過程中的異常。比如:輸入/輸出錯誤(IOException)、試圖為一個不存在的類找到一個代表它的class類的對象(ClassNotFoundException)等。這不是程序本身的錯誤,如果這些異常情況沒有發生,程序本身仍然是完好的。如果程序沒有適當地處理可能會引發運行異常的語句,則程序將不能通過編譯器的編譯。(一)RuntimeException類主要包括以下異常子類:·ArithmeticException算術異常類:表示遇到了異常的算術問題,例如被0整除。·ArrayStoreException數組內容異常類:試圖把與數組類型不相符的值存入數組。·ClassCastException類型強制轉換異常類:試圖把一個對象的引用強制轉換為不合適的類型。·IndexOutOfBoundsException下標越界異常類:下標越界。·NullPointerException空指針異常類:試圖使用一個空的對象引用。·SecurityException違背安全原則異常類:檢測到了違反安全的行為。
1.java.lang.ArithmeticException0作除數(包括模),將產生這類異常。例如:intx=0,y;y=100/x;
2.java.lang.ArrayIndexOutOfBoundsException
例如:inta[]=newint[10];a[10]=0;
產生運行時異常類對象舉例
3.
java.lang.ArrayStoreException例如:inta[]=newint[10];
booleanb[]=newboolean[10]; System.arraycopy(a,0,b,3,6);//有異常
4.java.lang.ClassCastException
例如:Objectobj=newObject();
inta[]=(int[])(obj);5.java.lang.NumerFormatException
例如:intj=Integer.parseInt(“abc”);
6.
java.lang.IndexOutOfBoundsException
例如:charch="ABC".charAt(99);
注意:2是6的子類。
7.java.lang.NegativeArraySizeException
例如:inta[]=newint[-10];
8.
java.lang.NullPointerException
例如:inta[]=null; System.out.print(a.length);
再如:inta[]=null;a[0]=1;1.IOException異常類IOException輸入輸出異常類,指示出現了某種I/O錯誤。這個類是由失敗的或中斷的I/O操作所產生的異常的總體類。IOException:申請I/O操作沒有正常完成。EOFException:在輸入操作正常結束前遇到了文件結束符。FileNotFoundException:在文件系統中,沒有找到由文件名字符串指定的文件。(二)Non-RuntimeException類主要包括以下異常子類:2.EmptyStackException:試圖訪問一個空堆棧中的元素。3.NoSuchFieldException:試圖訪問一個不存在的域。4.NoSuchMethodException:試圖訪問不存在的方法。5.ClassNotFoundException:具有指定名字的類或接口沒有被發現。6.CloneNotSupportedException:克隆一個沒有實現Cloneable接口的類。7.IllegalAccessException:試圖用給出了完整的路徑信息的字符串加載一個類。8.InstantiationException:試圖使用Class的newInstance方法創建一個對象實例。9.InterruptedException:當前的線程正在等待,而另一個線程使用了Thread的interrupt方法中斷了當前線程。(二)Non-RuntimeException類主要包括以下異常子類:五、程序對錯誤與異常的三種處理方式(1)程序不能處理錯誤(2)運行時異常——程序應避免而不捕獲異常(3)非運行時異常——必須捕獲異常對于程序無法預見的、由特殊環境錯誤造成的異常,如文件沒找到、網絡通信失敗等,必須進行捕獲和處理,從而保證程序正常運行,保證程序的可靠性和安全性。6.2Java的異常處理6.2.1異常處理機制的優點例6.1異常處理方法演示。publicclassExceptionDemo{ staticint[]IntArrayAdd(int[]a,int[]b) {
int[]c=newint[a.length];
for(inti=0;i<c.length;i++) c[i]=a[i]+b[i]; returnc;}
publicstaticvoidmain(String[]args) {
int[]a=newint[20];
int[]b=newint[10];
for(inti=0;i<20;i++) a[i]=i;
for(inti=0;i<10;i++) b[i]=i;
try{
int[]c=IntArrayAdd(a,b);
for(inti=0;i<c.length;i++) System.out.print(""+c[i]); }catch(Exceptione){
System.out.println("Thereisanerror!"); } }}程序運行結果為:
Thereisanerror!
從第2章有關數組的知識可以知道,程序6.1的main方法在調用方法IntArrayAdd對數組b訪問時下標超界,產生一個異常。由于程序6.1采用了Java語言中的異常處理方法,程序執行流程發生變化,轉到語句System.out.println(“Thereisanerror!”)執行。觀察一下程序6.1可以發現,程序中的錯誤在IntArrayAdd方法中發生,但是該方法中并沒有錯誤處理語句,既沒有用返回值標志錯誤發生,也沒有設置一個main方法和IntArrayAdd方法可以共同訪問的變量用于傳遞錯誤信息。那么,錯誤信息是怎樣從IntArrayAdd方法傳遞到main方法的呢?實際上IntArrayAdd方法在超界訪問數組元素時拋擲了一個異常,創建了一個異常對象用于存儲錯誤信息,由于IntArrayAdd方法沒有處理該異常,Java虛擬機終止IntArrayAdd方法的執行,然后自動返回到main方法,將流程轉入異常處理部分。Java語言的異常處理機制的優點(1)從語法上看,異常處理語句將程序正常代碼與錯誤代碼分開,使程序的結構清晰,算法重點突出,可讀性強。例如程序6.1的main方法中先調用IntArrayAdd方法然后輸出結果,中間并沒有插入錯誤處理的代碼,而按照傳統的方法,程序的結構應該是這樣的:調用IntArrayAdd方法:
if(發生錯誤)
輸出錯誤信息
else
輸出結果當錯誤類型較多,需要分別處理時,采用這種方法很顯然會使程序流程變得十分復雜。Java語言的異常處理機制的優點(2)異常處理機制帶來的另一個好處是錯誤的傳播。
Java異常會自動在方法調用堆棧中傳播,例如程序6.1異常從IntArrayAdd方法自動傳遞到main方法。(3)Java異常處理機制克服了傳統方法的錯誤信息有限的問題,可以針對不同的錯誤類型定義不同的異常類。
異常處理機制會根據異常對象的類型尋找匹配的錯誤處理代碼。(4)從運行效果看,異常處理語句使程序具有處理錯誤的能力。即使發生了運行錯,應用程序能夠捕獲異常并及時處理異常,使程序從運行錯誤中很好地恢復并繼續運行,而不會導致程序運行非正常終止。而且,如果當前方法沒有能力處理異常,還可以將異常轉交給調用者處理。6.2.2異常處理機制
Java提供了異常處理機制來處理異常。分為三個步驟:
1.拋出異常
Java是這樣規定的:當語義限制被違反時,將會拋出(throw)異常,即產生一個異常事件,生成一個異常對象,并把它提交給運行系統,再由運行系統尋找相應的代碼來處理異常。一個異常對象可以由Java虛擬機來產生,也可以由運行的方法生成。異常對象中包含了異常事件類型、程序運行狀態等必要信息。
2.捕獲異常異常拋出后,運行時系統從生成異常對象的代碼開始,沿方法的調用棧進行查找,直到找到包含相應處理的方法代碼,并把異常對象交給該方法為止,這個過程稱為捕獲(catch)異常。
3.處理異常對異常對象執行相應操作,異常對象由捕獲它的語句進行處理。
6.2.3異常的捕獲除了繼承自Error或RuntimeException的異常不需要處理之外,其他的異常都要進行處理,如例6.2。在程序中經常要做的一件事就是捕獲、處理異常。異常處理代碼塊(catch{})中可以寫上任何代碼,事實上只要對該捕獲的異常進行“catch”就可以,不作任何實質處理也可以通過編譯。例6.2缺省的異常處理的情況。
publicclassDefaultException{publicstaticvoidmain(Stringargs[]){
inta,b=0;
a=2/b;//此處有異常
System.out.println(“a=”+a);//不運行此行
}}異常處理的格式:try{//接受監視的程序塊,在此區域內發生的異常,由catch中指定的程序處理}//trycatch(異常類名1異常對象名1){//處理異常;}//catchcatch(異常類名2異常對象名2){//處理異常;}//catch……finally{//不論發生什么異常(或者不發生任何異常),都要執行的部分}//finally圖6.3異常處理語句的執行流程將可能發生異常的程序代碼放置在try程序塊中。程序運行過程中,如果該塊內的代碼沒有出現任何異常,則正常執行,后面的各catch塊不起任何作用。但如果該塊內的代碼出現了異常,系統將終止try塊的執行,自動跳轉到所發生的異常類對應的catch塊,執行該塊中的代碼。無論有沒有異常,finally語句都會被執行。如例6.3。catch子句捕獲異常的匹配規則如下:拋出異常對象與catch子句參數類型相同拋出異常對象為catch子句參數類的子類按照先后順序捕獲拋出異常對象,只捕獲一次若找不到相匹配的catch語句,將執行缺省的異常處理,如例6.4。因此,通常最后一個catch子句的異常類參數聲明為Exception,這樣能夠保證捕獲和處理所有異常對象。異常處理的格式說明:例6.3如果try塊內的代碼出現了異常,系統將終止try塊的執行,自動跳轉到所發生的異常類對應的catch塊。publicclassTryCatchTest{publicstaticvoidmain(Stringargs[]){
inta=99,b=0,c;
try{
System.out.println("產生異常之前"); c=a/b;//該行有異常
System.out.println("產生異常之后"); }catch(ArrayIndexOutOfBoundsExceptione){
System.out.println("處理下標越界異常"); }catch(ArithmeticExceptione){
System.out.println("處理算術異常"); }
System.out.println("異常處理結束");}}程序運行的結果:產生異常之前處理算術異常異常處理結束例6.4用catch語句捕捉異常時,若找不到相匹配的catch語句,將執行缺省的異常處理。publicclassTC2{publicstaticvoidmain(String[]args){
System.out.println(“這是一個異常處理的例子\n”);try{
inti=10;i/=0;}catch(IndexOutOfBoundsExceptione){
System.out.println("異常是:"+e.getMessage());}finally{
System.out.println("finally
語句被執行");}}}程序運行的結果:這是一個異常處理的例子對于一個try塊,可以對應多個catch塊,用于對多個異常類進行捕獲。每個catch后的異常類名應不同,Java語言根據異常對象的類型從上向下匹配,執行第一個與之匹配的catch塊。如果要捕獲的諸類之間沒有繼承關系,各類的catch塊的順序就無關緊要,但如果它們之間有繼承關系,那么應該將子類的catch塊放置在父類的catch塊之前。例如,當程序中數組下標超界時,Java拋擲出ArrayIndexOutOfBoundsExeption類的異常對象,該異常類是Exception的派生類,因此應將ArrayIndexOutOfBoundsExeption異常類的catch塊放在Exception的前面。異常處理的格式說明:inta[]=newint[10];try{
for(inti=0;i<=10;i++) a[i]=i;}catch(ArrayIndexOutOfBoundsExeptione){
System.out.println("ArrayIndexoutofBounds");}catch(Exceptione){
System.out.println("Thereisanexception");}該程序段將輸出:ArrayIndexoutofBounds而如果將兩個catch塊的順序對調,則變成下面的形式:inta[]=newint[10];try{for(inti=0;i<=10;i++) a[i]=i;}catch(Exceptione){
System.out.println("Thereisanexception");}
catch(ArrayIndexOutOfBoundsExeptione){
System.out.println("ArrayIndexoutofBounds");}將執行第一個catch塊,輸出:
Thereisanexception其中finally塊是個可選項,finally是異常處理的統一出口,如果有finally代碼塊,則不論怎樣都會執行finally代碼塊中的內容。因此,finally代碼塊中常常放一些清理現場的代碼,它可以保證不論出現什么異常都不致于造成嚴重后果。不過,finally代碼塊不是必須的,有些情況下并不必寫finally代碼塊。finally語句不被執行的唯一情況是在try塊內執行終止程序的System.exit()方法。注意:如果在調用能夠產生異常的方法時沒有進行捕獲和處理,將不能通過編譯。異常處理的格式說明:例6.5異常處理的執行順序。publicclassFinallyBlock{ publicstaticvoidmain(String[]args) {
inti=0; Stringgreetings[]={ "Helloworld!", "No,Imeanit!", "HELLOWORLD!!“};
while(i<4){ try{System.out.println(greetings[i]); }catch(ArrayIndexOutOfBoundsExceptione){
System.out.println("Re-settingIndexValue"); i=-1; }finally{
System.out.println("Thisisalwaysprinted"); } i++; } }}程序運行時重復輸出下面的內容,可按Ctrl+C終止:Helloworld!ThisisalwaysprintedNo,Imeanit!ThisisalwaysprintedHELLOWORLD!!ThisisalwaysprintedRe-settingIndexValueThisisalwaysprinted練習1:編寫程序。程序運行結果如下:捕獲算術異常!i=0a[1]/1=6i=1a[2]/2=3i=2a[3]/3=2i=3捕獲數組下標越界異常!i=4繼續!publicclassTry2{publicstaticvoidmain(Stringargs[]){
inti=0;
inta[]={5,6,7,8};
for(i=0;i<5;i++){try{
System.out.print("a["+i+"]/"+i+"="+(a[i]/i));}
catch(ArrayIndexOutOfBoundsExceptione){
System.out.print("捕獲數組下標越界異常!");}
catch(ArithmeticExceptione){
System.out.print("捕獲算術異常!");}
catch(Exceptione){
System.out.print("捕獲"+e.getMessage()+"異常!");//顯示異常信息}finally{
System.out.println("i="+i);}}
System.out.println("繼續!");}}TestNo:1
零作除數!在finally塊中!TestNo:2
數組下標越界!在finally塊中!TestNo:3
下標越界!在finally塊中!TestNo:4
在finally塊中!練習2:用for和switch編寫程序,程序運行結果如下:publicclasstestFinally{publicstaticvoidmain(Stringargs[]){
inta,b=0;
for(inti=0;i<=3;i++){
System.out.println("TestNo:"+(i+1));
try{ switch(i){ case0:a=3/b; break; case1:intc[]=newint[10]; c[10]=0; break; case2:charch="ABC".charAt(99); break; case3:return; } }catch(ArithmeticExceptione){
System.out.println(“零作除數!”); }catch(ArrayIndexOutOfBoundsExceptione){
System.out.println("數組下標越界!");}catch(IndexOutOfBoundsExceptione){
System.out.println("下標越界!");}finally{
System.out.println("在finally塊中!"); }}}}
6.2.4異常的拋擲上面講述的捕獲異常是針對程序在運行過程中產生的可以預知、必須及時處理而且有明確的處理對策的異常,其結果可以給用戶提供更多的、更友好的錯誤信息。但是有時也會碰到錯誤形式不確定的情況,隨之而來的是不能或很難完整描述具體處理的方法。對于這種在程序中不能匹配捕獲的異常,Java是不允許置之不理的,于是可以采取向外拋出的辦法。
1.throw語句
throw語句格式:
<throw><new><異常類名()>;
例如:
thrownewException();
該語句直接調用Exception類的構造方法創建一個Exception類的對象并拋擲該對象。
Exception類從Throwable類派生而來,含有兩個構造方法:
●publicException();●publicException(Stringmsg)。
根據錯誤類型的不同,創建的異常對象的類型也不相同。
throw語句的說明:
Throw語句是主動產生一個異常而非動態拋出。當程序執行到throw語句處,就立即人為地拋出一個異常,然后把控制轉移到一個相應的catch塊,不再執行throw后面的語句。在程序中使用throw語句來拋出異常,該異常可以在該程序中進行捕獲、處理;也可以在調用它的程序中被處理。例6.6throw語句的使用,運行結果如圖所示。publicclassTC5{staticvoidthrowProcess(){try{
thrownewNullPointerException("空指針異常");}
catch(NullPointerExceptione){
System.out.println("\n在throwProcess
方法中捕獲一個"+e.getMessage());
throwe;}}
publicstaticvoidmain(Stringargs[]){try{
throwProcess();}catch(NullPointerExceptione){
System.out.println("再次捕獲:"+e);}}}練習3:產生一個數組越界的異常,既在本方法體中處理,又通過throw語句將異常對象提交給調用者,以進行再次處理。程序運行結果如下:數組下標越界!下標越界!在finally塊中!
publicclassThrowException{publicstaticvoidTest(){ try{
intc[]=newint[10]; c[10]=0; }catch(ArrayIndexOutOfBoundsExceptione){
System.out.println("\t
數組下標越界!"); throwe;//拋出點
//System.out.println("\t產生異常后!"); } }publicstaticvoidmain(Stringargs[]){ try{
Test(); }catch(IndexOutOfBoundsExceptione){
System.out.println("\t
下標越界!"); }finally{
System.out.println("\t
在finally塊中!"); }}}
2.throws子句
Throws子句總是和方法說明出現在一起。方法說明告訴編譯器該方法可能會產生哪些異常,從而要求它的調用者必須考慮處理這些異常。一個方法不處理它產生的異常,而是沿著調用層次向上傳播,由調用它的方法來處理這些異常。建議:在多人合作寫程序時,一個方法中產生的異常,最好在該方法中進行處理,不要將異常傳播給其他人處理。圖7.2throws異常的拋出及處理方法一方法二異常調用拋出處理Throws子句格式:在方法定義的頭部加上:throws異常類名列表
<返回值類型><方法名><([參數])><throws><異常類名列表>{}例如:Thread類的方法sleep的定義為
publicstaticnativevoidsleep(longmills)throwsInterruptedException例6.7由調用者進行throws子句中的異常處理。importjava.io.*;publicclasstestThrows{publicstaticStringreadString()throws
IOException{
int
ch; Stringr="";
booleandone=false;
while(!done){
ch=System.in.read();
if(ch<0||ch==0xd)done=true; else r=r+(char)ch; } returnr;}Enter讀入緩沖區的字節總數,如果因為已經到達文件末尾而沒有更多的數據,則返回-1。
publicstaticvoidmain(Stringargs[]){ Stringstr; try{
str=readString(); }catch(IOExceptione){
System.out.println("產生了輸出/輸出異常"); return; }
System.out.println("整數是:"+Integer.parseInt(str));}}將字符串轉換成整數練習4:閱讀程序,說明程序運行的結果。classTC6{staticvoidmathod()throwsIllegalAccessException{
System.out.println("\n在mathod
中拋出一個異常");thrownewIllegalAccessException();}publicstaticvoidmain(Stringargs[]){try{
mathod();}catch(IllegalAccessExceptione){
System.out.println("在main中捕獲異常:"+e);}}}沒有訪問權限程序的運行結果如圖所示:練習5:編寫程序,在test()方法中使用5/0初始化intTemp,將觸發ArithmaticException異常,但test方法不對該異常捕獲和處理,而希望調用它的方法對該異常進行捕獲和處理。
3.拋出異常的綜合實例程序6.11演示了try-catch和throw語句的使用,該程序在KeyboardInput類中定義了兩個靜態方法ReadInt和ReadDouble,從標準輸入設備讀取int、double類型數據。首先調用ReadLine方法讀取一行字符串,然后將該字符串轉換為int、double類型數據。如果在轉換的過程中發生錯誤,輸入了錯誤的數據,則拋擲NumberFormatException類的異常,ReadInt和ReadDouble方法捕捉該異常,然后拋擲Exception異常。ExceptionDemo類在main方法中捕捉異常,調用Exception類的方法getMessage獲取錯誤信息。
例6.8異常處理實例。importjava.io.IOException;classKeyboardInput{ staticint
ReadInt()throwsException { Stringstr=ReadLine(); try{ returnnewInteger(str).intValue(); //將讀入的字符串轉換為int}catch(NumberFormatExceptione){ thrownewException("輸入數據錯誤"); } }
staticdoubleReadDouble()throwsException{ Stringstr=ReadLine(); try{ returnnewDouble(str).doubleValue();//將讀入的字符串轉換為double}catch(NumberFormatExceptione){ thrownewException("輸入數據錯誤"); } }
staticStringReadLine() { charin; Stringinputstr=""; try{in=(char)System.in.read(); while(in!='\n'){ if(in!='\r')
inputstr=inputstr+in; in=(char)System.in.read(); } }catch(IOExceptione){
inputstr=""; }returninputstr; }}\n表示回車\r表示換行publicclassExceptionDemo{ publicstaticvoidmain(String[]args) { try{
System.out.println("Theinputdoubleis"+KeyboardInput.ReadDouble());
System.out.println("Theinputintegeris"+KeyboardInput.ReadInt()); }catch(Exceptione){
System.out.println(e.getMessage()); } }}classTC7{staticvoidmathodA(){try{
System.out.println("\nmathodA
拋出一個異常");thrownewRuntimeException();}finally{
System.out.println("執行mathodA
的finally");}}練習6:閱讀程序,說明程序運行的結果。staticvoidmathodB(){try{
System.out.println("mathodB
正常返回");return;}finally{
System.out.println("執行mathodB
的finally");}}publicstaticvoidmain(Stringargs[]){try{
mathodA();}catch(Exceptione){mathodB();}}}程序的運行結果如圖所示:上例中finally子句的執行順序說明:當一個異常被拋出時,程序的執行就不再是連續的了,會跳過某些語句,甚至會由于沒有與之匹配的catch子句而過早地返回。有時要確保一段代碼不管發生什么異常都能被執行是必要的,finally子句就是用來標識這樣一段代碼的。即使沒有catch子句,finally語句塊也會在執行了try語句塊后立即被執行。每個try語句至少都要有一個與之相配的catch或finally子句。從一個方法返回到調用它的另外一個方法,或者是通過return語句,或者是通過一個沒有被捕獲的異常,但finally子句總是在返回前執行。練習7:編寫程序,編譯時對異常情況的檢查不是方法中產生的所有異常錯誤都必須被捕獲或聲明,Error和RuntimeException錯誤就不要求處理。Error屬于嚴重的系統錯誤,沒有辦法在程序中處理。而RuntimeException在運行時應該在編寫程序中避免發生錯誤。對于非運行時異常,則要求必須捕獲或聲明。也就是說,要么通過try-catch語句捕獲,要么將這些異常放在方法的throws語句中聲明,否則無法通過編譯。子類方法拋出的異常只能是父類方法拋出異常的同類或子類。也就是說,子類不能拋出比父類更多的異常。
6.3自定義異常類在選擇要拋出異常類型時,不一定非要使用Java平臺提供的異常類,更多的情況下是拋出程序員自己創建的異常,以滿足對某些特定應用環境下的異常處理需要。這就涉及異常的創建問題,即創建自己的異常。自定義異常類的格式:自定義異常類型是從Exception類中派生的,所以要使用下面的聲明語句來創建:
<class><自定義異常名><extends><Exception>{…}用戶定義異常類是通過派生Exception類來創建的,這種異常類可以包含一個“普通”類所包含的任何東西。下面就是一個用戶定義異常類的例子,它包含一個構造函數、幾個變量以及方法。例如:
classMyExceptionextendsException{privateint
ErrorCode;
MyException(int
ecode){super("自定義的異常類型");
ErrorCode=ecode;}publicint
getErrorCode(){ returnErrorCode;}}
定義上面的異常類后可以通過下面的語句拋擲MyException類的異常:thrownewMyException(1);通過繼承Exception類或它的子類,實現自定義異常類;對于自定義異常,必須采用throw語句拋出異常,這種類型的異常不會自行產生。總體上分為兩步:第1步:定義異常類。第2步:定義異常對象,并拋出該對象。第1步:定義異常類。例如:classuserExceptionextendsException{
intn=0;//計數器
userException(){n++; }
userException(Strings){ super(s); n++; }
Stringshow(){return"自定義異常對象:"+n; }}第2步:定義異常對象,并拋出該對象。例如:publicclasstestException{ staticvoidTest()throwsuserException{
userExceptione; e=newuserException("自定義異常"); throwe;
//=thrownewuserException("自定義異常"); } publicstaticvoidmain(Stringargs[]){ try{ Test(); }catch(userExceptione){
System.out.println(e.show()); } }}練習7:閱讀程序,說明程序運行的結果。<=0)}}例6.12異常類的定義、異常拋鄭和捕捉。程序運行后從鍵盤輸入10個英文字母,如果輸入非英文字母的字符,則拋擲自定義的notLetterException類型的異常。
importjava.io.IOException;
classnotLetterExceptionextendsException{ //異常類定義
publicnotLetterException(){ super("NotanEnglishletter"); }}publicclassgetLetter{ voidReadLetter(char[]s)throwsnotLetterException,IOException{ charc;
for(inti=0;i<s.length;i++){ c=(char)System.in.read(); if((c>='A'&&c<='Z')||(c>='a'&&c<='z')) s[i]=c; elsethrownewnotLetterException();//異常的拋擲
} }
publicstaticvoidmain(String[]args) { char[]s=newchar[10];
getLetterg=newgetLetter(); try{
g.ReadLetter(s); }catch(notLetterExceptione){//捕捉自定義的異常
System.out.println(e.getMessage()); }catch(IOExceptione){
System.out.println("I/Oerror"); } }}練習8:編寫程序,程序的運行結果如下圖。classMyExceptionextendsException{privateintx;
MyException(inta){x=a;}publicStringtoString(){return"MyException";}}publicclassTC8{staticvoidmathod(inta)throwsMyException{//聲明方法會拋出MyException
System.out.println("\t此處引用mathod("+a+")");if(a>10)thrownewMyException(a);//主動拋出
System.out.println("正常返回");}
publicstaticvoidmain(Stringargs[]){try{
System.out.println("\n進入監控區,執行可能發生異常的程序段");mathod(8);mathod(20);mathod(6);}catch(MyExceptione){
System.out.println("\t程序發生異常并在此處進行處理");
System.out.println("\t發生的異常為:"+e.toString());}
System.out.println("這里可執行其它代碼");}}
異常處理常用調試方法
在程序中增加輸出變量的信息。例如:System.out.println("x="+x);通過this輸出當前對象的狀態。例如:System.out.println(“對象:”+this);用printstackTrace()輸出異常對象的調用棧;用getMessage()方法獲取異常信息;用getClass()和getName()獲取異常類名。classuserExceptionextendsException{ publicuserException(){ super("自定義異常"); }}
publicclassgetMessages{ publicstaticvoidm1()throwsuserException{ m2(); } publicstaticvoidm2()throwsuserException{ thrownewuserException(); }例6.13異常處理的常用調試方法。publicstaticvoidmain(Stringargs[]){try{ m1();}catch(userExceptione){
System.out.println(e.getMessage());
e.printStackTrace();
System.out.println(“異常類型:”+
e.getClass().getName()); } }}程序輸出結果:自定義異常userException:自定義異常
atgetMessages.m2(getMessages.java:13)atgetMessages.m1(getMessages.java:10)atgetMessages.main(getMessages.java:19)異常類型:userException
異常處理的注意內容
當一個異常一直傳遞到main方法(程序調用的最高層)還沒有被捕獲,那么JVM將捕獲該異常并給出相應的異常信息且中止引發異常之后的操作,這對于用戶來說實際上就是程序已經崩潰。因此自定義的異常類名不宜放在main方法聲明時的throws列表中。Catch子句不能圖方便只寫catch(Exceptione){}。因為它將捕獲所有的異常,實際上無法給用戶提供實質性的異常提示信息,也不便于程序調試。編寫程序時對異常的處理與不處理的區別在于我們是否能夠控制所有的操作。例6.14比較兩個程序的運行結果。
publicclassA{publicstaticvoidmain(String[]args){
intb=0;b=12/0;//對異常不處理
System.out.println(“b=”+b);}}執行結果:Exceptioninthread“main”java.lang.ArithmeticException:/byzeroatA.main<A.java:4>
publicclassA{publicstaticvoidmain(String[]args){
intb=0;try{b=12/0;//對異常進行處理
}catch(ArithmeticExceptione){
e.printStackTrace(System.err);}
System.out.println(“b=”+b);}}執行結果:Java.lang.ArithmeticException:/byzeroatA.main<A.java:5>b=06.4編程實例程序6.14實現了一個簡易的計算器,該程序由兩個文件組成。文件Calculator.java中定義了一個類Calculator,該類用于實現計算器的功能,但不包括輸入輸出。文件AppCal.java中定義了類AppCal,其中包含main方法。AppCal的run方法從鍵盤接收輸入,調用Calculator的方法進行處理。例如,若從鍵盤輸入3+2*3,則程序按照輸入的順序計算,最后輸出結果15。【程序6.14】簡易計算器。//Calculator.javapublicclassCalculator{ privateintstatus=0;//計算器當前狀態
//0表示將已計算結果放入操作數1,等待運算符,或重新輸入操作數
//1表示正在輸入操作數1 //2表示已輸入運算符,等待輸入操作數2 //3表示正在輸入操作數2
privateStringnum1="0",num2="";//存儲運算數
privatecharOp;//存儲運算符
publicStringDisplayStr="0";//存儲運算結果
//計算器回到初始狀態
publicvoidinit() { status=0; num1="0";
DisplayStr="0"; }
//處理一個按鍵
voidKeyProcess(charkey){ switch(status){ case0:
if((key>='0'&&key<='9')||key=='.'){ status=1; num1=""+key;
DisplayStr=num1; } elseif(key=='+'||key=='-'||key=='*'||key=='/'){ Op=key; status=2;} break;
case1: if((key>='0'&&key<='9')||key=='.'){ status=1; num1=num1+key;
DisplayStr=num1; } elseif(key=='='){status=0; } elseif(key=='+'||key=='-'||key=='*'||key=='/'){ Op=key; status=2; } break;
case2: if((key>='0'&&key<='9')||key=='.'){ status=3; num2=""+key;
DisplayStr=num2; } elseif(key=='='){ status=0; } break;
case3: if((key>='0'&&key<='9')||key=='.'){ num2=num2+key;
DisplayStr=num2; } elseif(key=='='){ Cal();
DisplayStr=num1; status=0; }elseif(key=='+'||key=='-'||key=='*'||key=='/'){ Cal();
DisplayStr=num1; status=2; Op=key; } break; } }//計算結果
voidCal() { doublen1=newDouble(num1).doubleValue();//使用Double
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 臨床護理專業小組建設與管理
- 防火涂料包工協議書
- 節目演出安全協議書
- 飯店散伙轉讓協議書
- 訂單合同融資協議書
- 銀行股東分紅協議書
- 公交車聯合經營協議書
- 通校學生安全協議書
- 隔離酒店租用協議書
- 轉讓經營項目協議書
- 傳統節日端午節主題班會PPT模板
- 木材采購合同參考
- 胎漏、墮胎、滑胎、小產中醫護理常規
- 汽車發動機電控技術習題集答案
- 1389國開電大本科《理工英語4》網上形考任務(單元自測1至8)試題及答案(精華版)
- 居家環境安全評估量表-Microsoft-Word-文檔
- 設備供貨投標實施方案
- 地下室抗浮錨桿監理實施細則
- 高中數學導數知識點歸納總結
- 成本管理外文文獻及翻譯(共10頁)
- 電診斷在康復醫學中的應用ppt課件
評論
0/150
提交評論