JAVA 第六章 異常處理_第1頁
JAVA 第六章 異常處理_第2頁
JAVA 第六章 異常處理_第3頁
JAVA 第六章 異常處理_第4頁
JAVA 第六章 異常處理_第5頁
已閱讀5頁,還剩114頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第6章異常處理6.1程序錯(cuò)誤與處理6.2Java的異常處理6.3自定義異常類6.4編程實(shí)例 6.1程序錯(cuò)誤與處理程序中的錯(cuò)誤有不同的性質(zhì),不同的錯(cuò)誤需要采用不同的處理方式。按照錯(cuò)誤的性質(zhì)可將程序錯(cuò)誤分成3類:語法錯(cuò)、語義錯(cuò)、邏輯錯(cuò)。6.1.1程序錯(cuò)誤、發(fā)現(xiàn)時(shí)刻及錯(cuò)誤處理原則1.語法錯(cuò)違反語法規(guī)范的錯(cuò)誤稱為語法錯(cuò),這類錯(cuò)誤通常在編譯時(shí)發(fā)現(xiàn),又稱為編譯錯(cuò)。Java編譯器能夠發(fā)現(xiàn)所有語法錯(cuò),給出錯(cuò)誤的位置和性質(zhì)。程序員必須及時(shí)改正語法錯(cuò),再重新編譯程序。2.語義錯(cuò)如果程序在語法上正確,但在語義上存在錯(cuò)誤,則稱為語義錯(cuò),如除數(shù)為0錯(cuò)、給變量賦予超出其范圍的值、待打開的文件不存在等。語義錯(cuò)不能被編譯系統(tǒng)發(fā)現(xiàn),只能到程序運(yùn)行時(shí)才能被系統(tǒng)發(fā)現(xiàn),因而又稱為運(yùn)行錯(cuò)。在運(yùn)行時(shí),一旦發(fā)現(xiàn)了語義錯(cuò),Java將停止程序運(yùn)行,并給出錯(cuò)誤的位置和性質(zhì)。有些語義能夠被程序事先處理,程序中應(yīng)該設(shè)法避免產(chǎn)生這些錯(cuò)誤;還有一些語義錯(cuò)不能被程序事先處理,這些錯(cuò)誤的發(fā)生不由程序本身所控制,因此必須進(jìn)行異常處理。3.邏輯錯(cuò)如果程序通過編譯,可運(yùn)行,但運(yùn)行結(jié)果與期望值不符,則這類錯(cuò)誤稱為邏輯錯(cuò)。由于系統(tǒng)無法找到邏輯錯(cuò),所以邏輯錯(cuò)最難確定和排除。此時(shí),程序員必須憑借自身的程序設(shè)計(jì)經(jīng)驗(yàn),找到錯(cuò)誤原因及出錯(cuò)位置,從而改正錯(cuò)誤。6.1.2面向過程語言與面向?qū)ο笳Z言的錯(cuò)誤處理方式比較

面向過程語言——程序運(yùn)行效率更重要語言本身防范錯(cuò)誤的責(zé)任推給了程序員,使程序質(zhì)量完全依賴于程序員。程序員必須考慮并防范所有錯(cuò)誤,為每一個(gè)應(yīng)用程序設(shè)置語言一級(jí)的錯(cuò)誤處理機(jī)制,這對(duì)程序員的要求太高。再者,含有錯(cuò)誤處理的程序代碼臃腫,邏輯復(fù)雜,可讀性差,軟件無法維護(hù)和升級(jí)。在程序開發(fā)過程中,程序員能夠發(fā)現(xiàn)并改正語法錯(cuò)和邏輯錯(cuò),但無法防范所有運(yùn)行時(shí)錯(cuò)誤,這些錯(cuò)誤的出現(xiàn)不是由程序控制的,面向過程語言沒有提供對(duì)這些錯(cuò)誤的防范和處理機(jī)制,只能任憑錯(cuò)誤的產(chǎn)生而導(dǎo)致程序運(yùn)行中斷。

6.1.2面向過程語言與面向?qū)ο笳Z言的錯(cuò)誤處理方式比較面向?qū)ο笳Z言——程序的正確性、可靠性和穩(wěn)定性更重要提供語言級(jí)的錯(cuò)誤防范和處理機(jī)制,即異常處理機(jī)制。異常處理是捕獲和處理運(yùn)行時(shí)錯(cuò)誤的一種機(jī)制。異常處理機(jī)制使程序具有處理錯(cuò)誤的能力,即使發(fā)生了運(yùn)行時(shí)錯(cuò)誤,應(yīng)用程序能夠捕獲異常并及時(shí)處理異常,使程序從運(yùn)行時(shí)錯(cuò)誤中很好地恢復(fù)并繼續(xù)運(yùn)行,而不會(huì)導(dǎo)致程序運(yùn)行非正常終止。異常處理是一種對(duì)異常進(jìn)行事后處理的機(jī)制。異常處理機(jī)制將運(yùn)行時(shí)錯(cuò)誤封裝成若干錯(cuò)誤類和異常類,并提供異常處理語句用于在程序中實(shí)現(xiàn)對(duì)運(yùn)行時(shí)錯(cuò)誤的發(fā)現(xiàn)和及時(shí)處理。6.1.3Java的錯(cuò)誤和異常一、錯(cuò)誤與異常根據(jù)錯(cuò)誤的性質(zhì),Java將運(yùn)行時(shí)錯(cuò)誤分為兩類:錯(cuò)誤和異常。(1)錯(cuò)誤(error)錯(cuò)誤指程序運(yùn)行時(shí)遇到的硬件或操作系統(tǒng)的錯(cuò)誤,如內(nèi)存溢出、虛擬機(jī)錯(cuò)誤等。錯(cuò)誤對(duì)于程序而言是致命的,錯(cuò)誤將導(dǎo)致程序無法運(yùn)行,而且程序本身不能處理錯(cuò)誤,只能依靠外界干預(yù),否則會(huì)一直處于非正常狀態(tài)。(2)異常(exception)異常指在硬件和操作系統(tǒng)正常時(shí),程序遇到的運(yùn)行錯(cuò),如操作數(shù)超出數(shù)據(jù)范圍,文件不存在等。異常對(duì)于程序而言是非致命性的,雖然異常會(huì)導(dǎo)致程序非正常終止,但Java的異常處理機(jī)制使程序自身能夠捕獲和處理異常,由異常代碼調(diào)整程序運(yùn)行方向,但程序仍可繼續(xù)運(yùn)行。圖6.1Java程序發(fā)現(xiàn)錯(cuò)誤和異常二、錯(cuò)誤類和異常類Java中的所有的錯(cuò)誤類和異常類都是從Throwable類派生出來的。Throwable是異常類的根節(jié)點(diǎn),定義在java.lang包,它的子類也定義在該包中。Throwable類有兩個(gè)直接子類:java.lang.Error和java.lang.Exception。Error代表系統(tǒng)錯(cuò)誤類,由系統(tǒng)直接處理;Exception類及其子類是在程序中可捕捉到的異常。圖6.2錯(cuò)誤類和異常類的層次結(jié)構(gòu)(1)Error類Error類是錯(cuò)誤類,Error類對(duì)象由Java虛擬機(jī)生成并拋出給系統(tǒng),有內(nèi)存溢出錯(cuò)誤、棧溢出錯(cuò)誤、動(dòng)態(tài)鏈接錯(cuò)誤等。例如,當(dāng)運(yùn)行沒有main()方法的類時(shí),則產(chǎn)生類定義未找到錯(cuò)誤(NoClassDefFoundError)。(2)Exception類Exception類是異常類,Exception類對(duì)象是Java程序捕獲和處理的對(duì)象。每一種異常對(duì)應(yīng)Exception類的一個(gè)子類,異常對(duì)象中包含錯(cuò)誤的位置和特征信息。每個(gè)異常類反映一類運(yùn)行時(shí)錯(cuò)誤,類定義包含了該類異常的信息和對(duì)異常進(jìn)行處理的方法。Java預(yù)定了多種通用的異常類,如除數(shù)為0的算術(shù)異常、數(shù)組下標(biāo)越界異常、空指針異常等,程序中也可以自定義異常類。每當(dāng)程序運(yùn)行過程中發(fā)生了某個(gè)異?,F(xiàn)象,系統(tǒng)將產(chǎn)生一個(gè)相應(yīng)的異常類對(duì)象,并交由系統(tǒng)中的相應(yīng)機(jī)制進(jìn)行處理,以避免死機(jī)、死循環(huán)或其他對(duì)系統(tǒng)不利的結(jié)果發(fā)生,保證了程序運(yùn)行的安全性。三、Error錯(cuò)誤類的子類

Error類及其子類主要用來描述一些Java運(yùn)行時(shí)的系統(tǒng)內(nèi)部錯(cuò)誤或資源枯竭導(dǎo)致的錯(cuò)誤。普通的程序不能從這類錯(cuò)誤中恢復(fù),也無法拋出這種類型的錯(cuò)誤,這類錯(cuò)誤出現(xiàn)的幾率是很小的。

(1)VirtualMachineError虛擬機(jī)錯(cuò)誤OutOfMemoryError內(nèi)存溢出錯(cuò)誤StackOverflowError棧溢出錯(cuò)誤(2)LinkageError鏈接錯(cuò)誤(3)java.awt.AWTError圖形界面錯(cuò)誤

Throwable類的一個(gè)異常類分支是Exception類和它的子類。在編程中,對(duì)異常的處理主要是對(duì)這類異常的處理。類Exception是普通程序可以從中恢復(fù)的所有標(biāo)準(zhǔn)異常的超類。

Exception類又有兩個(gè)分支:從RuntimeException中派生出來的類和從Non-RuntimeException類中派生的類,這樣分類的根據(jù)是錯(cuò)誤發(fā)生的原因。

四、Exception異常類的子類(1)RuntimeException運(yùn)行時(shí)異常類,是程序員編寫程序不正確所導(dǎo)致的異常,理論上,程序員經(jīng)過檢查和測(cè)試可以查出這類錯(cuò)誤。該異常可能出現(xiàn)在程序的任何地方,而且出現(xiàn)的可能性非常大,如果由程序本身去檢測(cè)運(yùn)行異常出現(xiàn)與否,將會(huì)使程序的負(fù)荷過大,因而編譯器并不要求程序去說明或捕獲運(yùn)行時(shí)異常。(2)Non-RuntimeException非運(yùn)行時(shí)異常類,是由于一些異常的情況造成的,不是程序本身的錯(cuò)誤,可以由編譯器在編譯時(shí)檢測(cè)到的、可能會(huì)發(fā)生在方法執(zhí)行過程中的異常。比如:輸入/輸出錯(cuò)誤(IOException)、試圖為一個(gè)不存在的類找到一個(gè)代表它的class類的對(duì)象(ClassNotFoundException)等。這不是程序本身的錯(cuò)誤,如果這些異常情況沒有發(fā)生,程序本身仍然是完好的。如果程序沒有適當(dāng)?shù)靥幚砜赡軙?huì)引發(fā)運(yùn)行異常的語句,則程序?qū)⒉荒芡ㄟ^編譯器的編譯。(一)RuntimeException類主要包括以下異常子類:·ArithmeticException算術(shù)異常類:表示遇到了異常的算術(shù)問題,例如被0整除。·ArrayStoreException數(shù)組內(nèi)容異常類:試圖把與數(shù)組類型不相符的值存入數(shù)組?!lassCastException類型強(qiáng)制轉(zhuǎn)換異常類:試圖把一個(gè)對(duì)象的引用強(qiáng)制轉(zhuǎn)換為不合適的類型?!ndexOutOfBoundsException下標(biāo)越界異常類:下標(biāo)越界?!ullPointerException空指針異常類:試圖使用一個(gè)空的對(duì)象引用。·SecurityException違背安全原則異常類:檢測(cè)到了違反安全的行為。

1.java.lang.ArithmeticException0作除數(shù)(包括模),將產(chǎn)生這類異常。例如:intx=0,y;y=100/x;

2.java.lang.ArrayIndexOutOfBoundsException

例如:inta[]=newint[10];a[10]=0;

產(chǎn)生運(yùn)行時(shí)異常類對(duì)象舉例

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輸入輸出異常類,指示出現(xiàn)了某種I/O錯(cuò)誤。這個(gè)類是由失敗的或中斷的I/O操作所產(chǎn)生的異常的總體類。IOException:申請(qǐng)I/O操作沒有正常完成。EOFException:在輸入操作正常結(jié)束前遇到了文件結(jié)束符。FileNotFoundException:在文件系統(tǒng)中,沒有找到由文件名字符串指定的文件。(二)Non-RuntimeException類主要包括以下異常子類:2.EmptyStackException:試圖訪問一個(gè)空堆棧中的元素。3.NoSuchFieldException:試圖訪問一個(gè)不存在的域。4.NoSuchMethodException:試圖訪問不存在的方法。5.ClassNotFoundException:具有指定名字的類或接口沒有被發(fā)現(xiàn)。6.CloneNotSupportedException:克隆一個(gè)沒有實(shí)現(xiàn)Cloneable接口的類。7.IllegalAccessException:試圖用給出了完整的路徑信息的字符串加載一個(gè)類。8.InstantiationException:試圖使用Class的newInstance方法創(chuàng)建一個(gè)對(duì)象實(shí)例。9.InterruptedException:當(dāng)前的線程正在等待,而另一個(gè)線程使用了Thread的interrupt方法中斷了當(dāng)前線程。(二)Non-RuntimeException類主要包括以下異常子類:五、程序?qū)﹀e(cuò)誤與異常的三種處理方式(1)程序不能處理錯(cuò)誤(2)運(yùn)行時(shí)異?!绦驊?yīng)避免而不捕獲異常(3)非運(yùn)行時(shí)異?!仨毑东@異常對(duì)于程序無法預(yù)見的、由特殊環(huán)境錯(cuò)誤造成的異常,如文件沒找到、網(wǎng)絡(luò)通信失敗等,必須進(jìn)行捕獲和處理,從而保證程序正常運(yùn)行,保證程序的可靠性和安全性。6.2Java的異常處理6.2.1異常處理機(jī)制的優(yōu)點(diǎn)例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!"); } }}程序運(yùn)行結(jié)果為:

Thereisanerror!

從第2章有關(guān)數(shù)組的知識(shí)可以知道,程序6.1的main方法在調(diào)用方法IntArrayAdd對(duì)數(shù)組b訪問時(shí)下標(biāo)超界,產(chǎn)生一個(gè)異常。由于程序6.1采用了Java語言中的異常處理方法,程序執(zhí)行流程發(fā)生變化,轉(zhuǎn)到語句System.out.println(“Thereisanerror!”)執(zhí)行。觀察一下程序6.1可以發(fā)現(xiàn),程序中的錯(cuò)誤在IntArrayAdd方法中發(fā)生,但是該方法中并沒有錯(cuò)誤處理語句,既沒有用返回值標(biāo)志錯(cuò)誤發(fā)生,也沒有設(shè)置一個(gè)main方法和IntArrayAdd方法可以共同訪問的變量用于傳遞錯(cuò)誤信息。那么,錯(cuò)誤信息是怎樣從IntArrayAdd方法傳遞到main方法的呢?實(shí)際上IntArrayAdd方法在超界訪問數(shù)組元素時(shí)拋擲了一個(gè)異常,創(chuàng)建了一個(gè)異常對(duì)象用于存儲(chǔ)錯(cuò)誤信息,由于IntArrayAdd方法沒有處理該異常,Java虛擬機(jī)終止IntArrayAdd方法的執(zhí)行,然后自動(dòng)返回到main方法,將流程轉(zhuǎn)入異常處理部分。Java語言的異常處理機(jī)制的優(yōu)點(diǎn)(1)從語法上看,異常處理語句將程序正常代碼與錯(cuò)誤代碼分開,使程序的結(jié)構(gòu)清晰,算法重點(diǎn)突出,可讀性強(qiáng)。例如程序6.1的main方法中先調(diào)用IntArrayAdd方法然后輸出結(jié)果,中間并沒有插入錯(cuò)誤處理的代碼,而按照傳統(tǒng)的方法,程序的結(jié)構(gòu)應(yīng)該是這樣的:調(diào)用IntArrayAdd方法:

if(發(fā)生錯(cuò)誤)

輸出錯(cuò)誤信息

else

輸出結(jié)果當(dāng)錯(cuò)誤類型較多,需要分別處理時(shí),采用這種方法很顯然會(huì)使程序流程變得十分復(fù)雜。Java語言的異常處理機(jī)制的優(yōu)點(diǎn)(2)異常處理機(jī)制帶來的另一個(gè)好處是錯(cuò)誤的傳播。

Java異常會(huì)自動(dòng)在方法調(diào)用堆棧中傳播,例如程序6.1異常從IntArrayAdd方法自動(dòng)傳遞到main方法。(3)Java異常處理機(jī)制克服了傳統(tǒng)方法的錯(cuò)誤信息有限的問題,可以針對(duì)不同的錯(cuò)誤類型定義不同的異常類。

異常處理機(jī)制會(huì)根據(jù)異常對(duì)象的類型尋找匹配的錯(cuò)誤處理代碼。(4)從運(yùn)行效果看,異常處理語句使程序具有處理錯(cuò)誤的能力。即使發(fā)生了運(yùn)行錯(cuò),應(yīng)用程序能夠捕獲異常并及時(shí)處理異常,使程序從運(yùn)行錯(cuò)誤中很好地恢復(fù)并繼續(xù)運(yùn)行,而不會(huì)導(dǎo)致程序運(yùn)行非正常終止。而且,如果當(dāng)前方法沒有能力處理異常,還可以將異常轉(zhuǎn)交給調(diào)用者處理。6.2.2異常處理機(jī)制

Java提供了異常處理機(jī)制來處理異常。分為三個(gè)步驟:

1.拋出異常

Java是這樣規(guī)定的:當(dāng)語義限制被違反時(shí),將會(huì)拋出(throw)異常,即產(chǎn)生一個(gè)異常事件,生成一個(gè)異常對(duì)象,并把它提交給運(yùn)行系統(tǒng),再由運(yùn)行系統(tǒng)尋找相應(yīng)的代碼來處理異常。一個(gè)異常對(duì)象可以由Java虛擬機(jī)來產(chǎn)生,也可以由運(yùn)行的方法生成。異常對(duì)象中包含了異常事件類型、程序運(yùn)行狀態(tài)等必要信息。

2.捕獲異常異常拋出后,運(yùn)行時(shí)系統(tǒng)從生成異常對(duì)象的代碼開始,沿方法的調(diào)用棧進(jìn)行查找,直到找到包含相應(yīng)處理的方法代碼,并把異常對(duì)象交給該方法為止,這個(gè)過程稱為捕獲(catch)異常。

3.處理異常對(duì)異常對(duì)象執(zhí)行相應(yīng)操作,異常對(duì)象由捕獲它的語句進(jìn)行處理。

6.2.3異常的捕獲除了繼承自Error或RuntimeException的異常不需要處理之外,其他的異常都要進(jìn)行處理,如例6.2。在程序中經(jīng)常要做的一件事就是捕獲、處理異常。異常處理代碼塊(catch{})中可以寫上任何代碼,事實(shí)上只要對(duì)該捕獲的異常進(jìn)行“catch”就可以,不作任何實(shí)質(zhì)處理也可以通過編譯。例6.2缺省的異常處理的情況。

publicclassDefaultException{publicstaticvoidmain(Stringargs[]){

inta,b=0;

a=2/b;//此處有異常

System.out.println(“a=”+a);//不運(yùn)行此行

}}異常處理的格式:try{//接受監(jiān)視的程序塊,在此區(qū)域內(nèi)發(fā)生的異常,由catch中指定的程序處理}//trycatch(異常類名1異常對(duì)象名1){//處理異常;}//catchcatch(異常類名2異常對(duì)象名2){//處理異常;}//catch……finally{//不論發(fā)生什么異常(或者不發(fā)生任何異常),都要執(zhí)行的部分}//finally圖6.3異常處理語句的執(zhí)行流程將可能發(fā)生異常的程序代碼放置在try程序塊中。程序運(yùn)行過程中,如果該塊內(nèi)的代碼沒有出現(xiàn)任何異常,則正常執(zhí)行,后面的各catch塊不起任何作用。但如果該塊內(nèi)的代碼出現(xiàn)了異常,系統(tǒng)將終止try塊的執(zhí)行,自動(dòng)跳轉(zhuǎn)到所發(fā)生的異常類對(duì)應(yīng)的catch塊,執(zhí)行該塊中的代碼。無論有沒有異常,finally語句都會(huì)被執(zhí)行。如例6.3。catch子句捕獲異常的匹配規(guī)則如下:拋出異常對(duì)象與catch子句參數(shù)類型相同拋出異常對(duì)象為catch子句參數(shù)類的子類按照先后順序捕獲拋出異常對(duì)象,只捕獲一次若找不到相匹配的catch語句,將執(zhí)行缺省的異常處理,如例6.4。因此,通常最后一個(gè)catch子句的異常類參數(shù)聲明為Exception,這樣能夠保證捕獲和處理所有異常對(duì)象。異常處理的格式說明:例6.3如果try塊內(nèi)的代碼出現(xiàn)了異常,系統(tǒng)將終止try塊的執(zhí)行,自動(dòng)跳轉(zhuǎn)到所發(fā)生的異常類對(duì)應(yīng)的catch塊。publicclassTryCatchTest{publicstaticvoidmain(Stringargs[]){

inta=99,b=0,c;

try{

System.out.println("產(chǎn)生異常之前"); c=a/b;//該行有異常

System.out.println("產(chǎn)生異常之后"); }catch(ArrayIndexOutOfBoundsExceptione){

System.out.println("處理下標(biāo)越界異常"); }catch(ArithmeticExceptione){

System.out.println("處理算術(shù)異常"); }

System.out.println("異常處理結(jié)束");}}程序運(yùn)行的結(jié)果:產(chǎn)生異常之前處理算術(shù)異常異常處理結(jié)束例6.4用catch語句捕捉異常時(shí),若找不到相匹配的catch語句,將執(zhí)行缺省的異常處理。publicclassTC2{publicstaticvoidmain(String[]args){

System.out.println(“這是一個(gè)異常處理的例子\n”);try{

inti=10;i/=0;}catch(IndexOutOfBoundsExceptione){

System.out.println("異常是:"+e.getMessage());}finally{

System.out.println("finally

語句被執(zhí)行");}}}程序運(yùn)行的結(jié)果:這是一個(gè)異常處理的例子對(duì)于一個(gè)try塊,可以對(duì)應(yīng)多個(gè)catch塊,用于對(duì)多個(gè)異常類進(jìn)行捕獲。每個(gè)catch后的異常類名應(yīng)不同,Java語言根據(jù)異常對(duì)象的類型從上向下匹配,執(zhí)行第一個(gè)與之匹配的catch塊。如果要捕獲的諸類之間沒有繼承關(guān)系,各類的catch塊的順序就無關(guān)緊要,但如果它們之間有繼承關(guān)系,那么應(yīng)該將子類的catch塊放置在父類的catch塊之前。例如,當(dāng)程序中數(shù)組下標(biāo)超界時(shí),Java拋擲出ArrayIndexOutOfBoundsExeption類的異常對(duì)象,該異常類是Exception的派生類,因此應(yīng)將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而如果將兩個(gè)catch塊的順序?qū)φ{(diào),則變成下面的形式: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");}將執(zhí)行第一個(gè)catch塊,輸出:

Thereisanexception其中finally塊是個(gè)可選項(xiàng),finally是異常處理的統(tǒng)一出口,如果有finally代碼塊,則不論怎樣都會(huì)執(zhí)行finally代碼塊中的內(nèi)容。因此,finally代碼塊中常常放一些清理現(xiàn)場(chǎng)的代碼,它可以保證不論出現(xiàn)什么異常都不致于造成嚴(yán)重后果。不過,finally代碼塊不是必須的,有些情況下并不必寫finally代碼塊。finally語句不被執(zhí)行的唯一情況是在try塊內(nèi)執(zhí)行終止程序的System.exit()方法。注意:如果在調(diào)用能夠產(chǎn)生異常的方法時(shí)沒有進(jìn)行捕獲和處理,將不能通過編譯。異常處理的格式說明:例6.5異常處理的執(zhí)行順序。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++; } }}程序運(yùn)行時(shí)重復(fù)輸出下面的內(nèi)容,可按Ctrl+C終止:Helloworld!ThisisalwaysprintedNo,Imeanit!ThisisalwaysprintedHELLOWORLD!!ThisisalwaysprintedRe-settingIndexValueThisisalwaysprinted練習(xí)1:編寫程序。程序運(yùn)行結(jié)果如下:捕獲算術(shù)異常!i=0a[1]/1=6i=1a[2]/2=3i=2a[3]/3=2i=3捕獲數(shù)組下標(biāo)越界異常!i=4繼續(xù)!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("捕獲數(shù)組下標(biāo)越界異常!");}

catch(ArithmeticExceptione){

System.out.print("捕獲算術(shù)異常!");}

catch(Exceptione){

System.out.print("捕獲"+e.getMessage()+"異常!");//顯示異常信息}finally{

System.out.println("i="+i);}}

System.out.println("繼續(xù)!");}}TestNo:1

零作除數(shù)!在finally塊中!TestNo:2

數(shù)組下標(biāo)越界!在finally塊中!TestNo:3

下標(biāo)越界!在finally塊中!TestNo:4

在finally塊中!練習(xí)2:用for和switch編寫程序,程序運(yùn)行結(jié)果如下: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(“零作除數(shù)!”); }catch(ArrayIndexOutOfBoundsExceptione){

System.out.println("數(shù)組下標(biāo)越界!");}catch(IndexOutOfBoundsExceptione){

System.out.println("下標(biāo)越界!");}finally{

System.out.println("在finally塊中!"); }}}}

6.2.4異常的拋擲上面講述的捕獲異常是針對(duì)程序在運(yùn)行過程中產(chǎn)生的可以預(yù)知、必須及時(shí)處理而且有明確的處理對(duì)策的異常,其結(jié)果可以給用戶提供更多的、更友好的錯(cuò)誤信息。但是有時(shí)也會(huì)碰到錯(cuò)誤形式不確定的情況,隨之而來的是不能或很難完整描述具體處理的方法。對(duì)于這種在程序中不能匹配捕獲的異常,Java是不允許置之不理的,于是可以采取向外拋出的辦法。

1.throw語句

throw語句格式:

<throw><new><異常類名()>;

例如:

thrownewException();

該語句直接調(diào)用Exception類的構(gòu)造方法創(chuàng)建一個(gè)Exception類的對(duì)象并拋擲該對(duì)象。

Exception類從Throwable類派生而來,含有兩個(gè)構(gòu)造方法:

●publicException();●publicException(Stringmsg)。

根據(jù)錯(cuò)誤類型的不同,創(chuàng)建的異常對(duì)象的類型也不相同。

throw語句的說明:

Throw語句是主動(dòng)產(chǎn)生一個(gè)異常而非動(dòng)態(tài)拋出。當(dāng)程序執(zhí)行到throw語句處,就立即人為地拋出一個(gè)異常,然后把控制轉(zhuǎn)移到一個(gè)相應(yīng)的catch塊,不再執(zhí)行throw后面的語句。在程序中使用throw語句來拋出異常,該異??梢栽谠摮绦蛑羞M(jìn)行捕獲、處理;也可以在調(diào)用它的程序中被處理。例6.6throw語句的使用,運(yùn)行結(jié)果如圖所示。publicclassTC5{staticvoidthrowProcess(){try{

thrownewNullPointerException("空指針異常");}

catch(NullPointerExceptione){

System.out.println("\n在throwProcess

方法中捕獲一個(gè)"+e.getMessage());

throwe;}}

publicstaticvoidmain(Stringargs[]){try{

throwProcess();}catch(NullPointerExceptione){

System.out.println("再次捕獲:"+e);}}}練習(xí)3:產(chǎn)生一個(gè)數(shù)組越界的異常,既在本方法體中處理,又通過throw語句將異常對(duì)象提交給調(diào)用者,以進(jìn)行再次處理。程序運(yùn)行結(jié)果如下:數(shù)組下標(biāo)越界!下標(biāo)越界!在finally塊中!

publicclassThrowException{publicstaticvoidTest(){ try{

intc[]=newint[10]; c[10]=0; }catch(ArrayIndexOutOfBoundsExceptione){

System.out.println("\t

數(shù)組下標(biāo)越界!"); throwe;//拋出點(diǎn)

//System.out.println("\t產(chǎn)生異常后!"); } }publicstaticvoidmain(Stringargs[]){ try{

Test(); }catch(IndexOutOfBoundsExceptione){

System.out.println("\t

下標(biāo)越界!"); }finally{

System.out.println("\t

在finally塊中!"); }}}

2.throws子句

Throws子句總是和方法說明出現(xiàn)在一起。方法說明告訴編譯器該方法可能會(huì)產(chǎn)生哪些異常,從而要求它的調(diào)用者必須考慮處理這些異常。一個(gè)方法不處理它產(chǎn)生的異常,而是沿著調(diào)用層次向上傳播,由調(diào)用它的方法來處理這些異常。建議:在多人合作寫程序時(shí),一個(gè)方法中產(chǎn)生的異常,最好在該方法中進(jìn)行處理,不要將異常傳播給其他人處理。圖7.2throws異常的拋出及處理方法一方法二異常調(diào)用拋出處理Throws子句格式:在方法定義的頭部加上:throws異常類名列表

<返回值類型><方法名><([參數(shù)])><throws><異常類名列表>{}例如:Thread類的方法sleep的定義為

publicstaticnativevoidsleep(longmills)throwsInterruptedException例6.7由調(diào)用者進(jìn)行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讀入緩沖區(qū)的字節(jié)總數(shù),如果因?yàn)橐呀?jīng)到達(dá)文件末尾而沒有更多的數(shù)據(jù),則返回-1。

publicstaticvoidmain(Stringargs[]){ Stringstr; try{

str=readString(); }catch(IOExceptione){

System.out.println("產(chǎn)生了輸出/輸出異常"); return; }

System.out.println("整數(shù)是:"+Integer.parseInt(str));}}將字符串轉(zhuǎn)換成整數(shù)練習(xí)4:閱讀程序,說明程序運(yùn)行的結(jié)果。classTC6{staticvoidmathod()throwsIllegalAccessException{

System.out.println("\n在mathod

中拋出一個(gè)異常");thrownewIllegalAccessException();}publicstaticvoidmain(Stringargs[]){try{

mathod();}catch(IllegalAccessExceptione){

System.out.println("在main中捕獲異常:"+e);}}}沒有訪問權(quán)限程序的運(yùn)行結(jié)果如圖所示:練習(xí)5:編寫程序,在test()方法中使用5/0初始化intTemp,將觸發(fā)ArithmaticException異常,但test方法不對(duì)該異常捕獲和處理,而希望調(diào)用它的方法對(duì)該異常進(jìn)行捕獲和處理。

3.拋出異常的綜合實(shí)例程序6.11演示了try-catch和throw語句的使用,該程序在KeyboardInput類中定義了兩個(gè)靜態(tài)方法ReadInt和ReadDouble,從標(biāo)準(zhǔn)輸入設(shè)備讀取int、double類型數(shù)據(jù)。首先調(diào)用ReadLine方法讀取一行字符串,然后將該字符串轉(zhuǎn)換為int、double類型數(shù)據(jù)。如果在轉(zhuǎn)換的過程中發(fā)生錯(cuò)誤,輸入了錯(cuò)誤的數(shù)據(jù),則拋擲NumberFormatException類的異常,ReadInt和ReadDouble方法捕捉該異常,然后拋擲Exception異常。ExceptionDemo類在main方法中捕捉異常,調(diào)用Exception類的方法getMessage獲取錯(cuò)誤信息。

例6.8異常處理實(shí)例。importjava.io.IOException;classKeyboardInput{ staticint

ReadInt()throwsException { Stringstr=ReadLine(); try{ returnnewInteger(str).intValue(); //將讀入的字符串轉(zhuǎn)換為int}catch(NumberFormatExceptione){ thrownewException("輸入數(shù)據(jù)錯(cuò)誤"); } }

staticdoubleReadDouble()throwsException{ Stringstr=ReadLine(); try{ returnnewDouble(str).doubleValue();//將讀入的字符串轉(zhuǎn)換為double}catch(NumberFormatExceptione){ thrownewException("輸入數(shù)據(jù)錯(cuò)誤"); } }

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

拋出一個(gè)異常");thrownewRuntimeException();}finally{

System.out.println("執(zhí)行mathodA

的finally");}}練習(xí)6:閱讀程序,說明程序運(yùn)行的結(jié)果。staticvoidmathodB(){try{

System.out.println("mathodB

正常返回");return;}finally{

System.out.println("執(zhí)行mathodB

的finally");}}publicstaticvoidmain(Stringargs[]){try{

mathodA();}catch(Exceptione){mathodB();}}}程序的運(yùn)行結(jié)果如圖所示:上例中finally子句的執(zhí)行順序說明:當(dāng)一個(gè)異常被拋出時(shí),程序的執(zhí)行就不再是連續(xù)的了,會(huì)跳過某些語句,甚至?xí)捎跊]有與之匹配的catch子句而過早地返回。有時(shí)要確保一段代碼不管發(fā)生什么異常都能被執(zhí)行是必要的,finally子句就是用來標(biāo)識(shí)這樣一段代碼的。即使沒有catch子句,finally語句塊也會(huì)在執(zhí)行了try語句塊后立即被執(zhí)行。每個(gè)try語句至少都要有一個(gè)與之相配的catch或finally子句。從一個(gè)方法返回到調(diào)用它的另外一個(gè)方法,或者是通過return語句,或者是通過一個(gè)沒有被捕獲的異常,但finally子句總是在返回前執(zhí)行。練習(xí)7:編寫程序,編譯時(shí)對(duì)異常情況的檢查不是方法中產(chǎn)生的所有異常錯(cuò)誤都必須被捕獲或聲明,Error和RuntimeException錯(cuò)誤就不要求處理。Error屬于嚴(yán)重的系統(tǒng)錯(cuò)誤,沒有辦法在程序中處理。而RuntimeException在運(yùn)行時(shí)應(yīng)該在編寫程序中避免發(fā)生錯(cuò)誤。對(duì)于非運(yùn)行時(shí)異常,則要求必須捕獲或聲明。也就是說,要么通過try-catch語句捕獲,要么將這些異常放在方法的throws語句中聲明,否則無法通過編譯。子類方法拋出的異常只能是父類方法拋出異常的同類或子類。也就是說,子類不能拋出比父類更多的異常。

6.3自定義異常類在選擇要拋出異常類型時(shí),不一定非要使用Java平臺(tái)提供的異常類,更多的情況下是拋出程序員自己創(chuàng)建的異常,以滿足對(duì)某些特定應(yīng)用環(huán)境下的異常處理需要。這就涉及異常的創(chuàng)建問題,即創(chuàng)建自己的異常。自定義異常類的格式:自定義異常類型是從Exception類中派生的,所以要使用下面的聲明語句來創(chuàng)建:

<class><自定義異常名><extends><Exception>{…}用戶定義異常類是通過派生Exception類來創(chuàng)建的,這種異常類可以包含一個(gè)“普通”類所包含的任何東西。下面就是一個(gè)用戶定義異常類的例子,它包含一個(gè)構(gòu)造函數(shù)、幾個(gè)變量以及方法。例如:

classMyExceptionextendsException{privateint

ErrorCode;

MyException(int

ecode){super("自定義的異常類型");

ErrorCode=ecode;}publicint

getErrorCode(){ returnErrorCode;}}

定義上面的異常類后可以通過下面的語句拋擲MyException類的異常:thrownewMyException(1);通過繼承Exception類或它的子類,實(shí)現(xiàn)自定義異常類;對(duì)于自定義異常,必須采用throw語句拋出異常,這種類型的異常不會(huì)自行產(chǎn)生??傮w上分為兩步:第1步:定義異常類。第2步:定義異常對(duì)象,并拋出該對(duì)象。第1步:定義異常類。例如:classuserExceptionextendsException{

intn=0;//計(jì)數(shù)器

userException(){n++; }

userException(Strings){ super(s); n++; }

Stringshow(){return"自定義異常對(duì)象:"+n; }}第2步:定義異常對(duì)象,并拋出該對(duì)象。例如:publicclasstestException{ staticvoidTest()throwsuserException{

userExceptione; e=newuserException("自定義異常"); throwe;

//=thrownewuserException("自定義異常"); } publicstaticvoidmain(Stringargs[]){ try{ Test(); }catch(userExceptione){

System.out.println(e.show()); } }}練習(xí)7:閱讀程序,說明程序運(yùn)行的結(jié)果。<=0)}}例6.12異常類的定義、異常拋鄭和捕捉。程序運(yùn)行后從鍵盤輸入10個(gè)英文字母,如果輸入非英文字母的字符,則拋擲自定義的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"); } }}練習(xí)8:編寫程序,程序的運(yùn)行結(jié)果如下圖。classMyExceptionextendsException{privateintx;

MyException(inta){x=a;}publicStringtoString(){return"MyException";}}publicclassTC8{staticvoidmathod(inta)throwsMyException{//聲明方法會(huì)拋出MyException

System.out.println("\t此處引用mathod("+a+")");if(a>10)thrownewMyException(a);//主動(dòng)拋出

System.out.println("正常返回");}

publicstaticvoidmain(Stringargs[]){try{

System.out.println("\n進(jìn)入監(jiān)控區(qū),執(zhí)行可能發(fā)生異常的程序段");mathod(8);mathod(20);mathod(6);}catch(MyExceptione){

System.out.println("\t程序發(fā)生異常并在此處進(jìn)行處理");

System.out.println("\t發(fā)生的異常為:"+e.toString());}

System.out.println("這里可執(zhí)行其它代碼");}}

異常處理常用調(diào)試方法

在程序中增加輸出變量的信息。例如:System.out.println("x="+x);通過this輸出當(dāng)前對(duì)象的狀態(tài)。例如:System.out.println(“對(duì)象:”+this);用printstackTrace()輸出異常對(duì)象的調(diào)用棧;用getMessage()方法獲取異常信息;用getClass()和getName()獲取異常類名。classuserExceptionextendsException{ publicuserException(){ super("自定義異常"); }}

publicclassgetMessages{ publicstaticvoidm1()throwsuserException{ m2(); } publicstaticvoidm2()throwsuserException{ thrownewuserException(); }例6.13異常處理的常用調(diào)試方法。publicstaticvoidmain(Stringargs[]){try{ m1();}catch(userExceptione){

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

e.printStackTrace();

System.out.println(“異常類型:”+

e.getClass().getName()); } }}程序輸出結(jié)果:自定義異常userException:自定義異常

atgetMessages.m2(getMessages.java:13)atgetMessages.m1(getMessages.java:10)atgetMessages.main(getMessages.java:19)異常類型:userException

異常處理的注意內(nèi)容

當(dāng)一個(gè)異常一直傳遞到main方法(程序調(diào)用的最高層)還沒有被捕獲,那么JVM將捕獲該異常并給出相應(yīng)的異常信息且中止引發(fā)異常之后的操作,這對(duì)于用戶來說實(shí)際上就是程序已經(jīng)崩潰。因此自定義的異常類名不宜放在main方法聲明時(shí)的throws列表中。Catch子句不能圖方便只寫catch(Exceptione){}。因?yàn)樗鼘⒉东@所有的異常,實(shí)際上無法給用戶提供實(shí)質(zhì)性的異常提示信息,也不便于程序調(diào)試。編寫程序時(shí)對(duì)異常的處理與不處理的區(qū)別在于我們是否能夠控制所有的操作。例6.14比較兩個(gè)程序的運(yùn)行結(jié)果。

publicclassA{publicstaticvoidmain(String[]args){

intb=0;b=12/0;//對(duì)異常不處理

System.out.println(“b=”+b);}}執(zhí)行結(jié)果:Exceptioninthread“main”java.lang.ArithmeticException:/byzeroatA.main<A.java:4>

publicclassA{publicstaticvoidmain(String[]args){

intb=0;try{b=12/0;//對(duì)異常進(jìn)行處理

}catch(ArithmeticExceptione){

e.printStackTrace(System.err);}

System.out.println(“b=”+b);}}執(zhí)行結(jié)果:Java.lang.ArithmeticException:/byzeroatA.main<A.java:5>b=06.4編程實(shí)例程序6.14實(shí)現(xiàn)了一個(gè)簡(jiǎn)易的計(jì)算器,該程序由兩個(gè)文件組成。文件Calculator.java中定義了一個(gè)類Calculator,該類用于實(shí)現(xiàn)計(jì)算器的功能,但不包括輸入輸出。文件AppCal.java中定義了類AppCal,其中包含main方法。AppCal的run方法從鍵盤接收輸入,調(diào)用Calculator的方法進(jìn)行處理。例如,若從鍵盤輸入3+2*3,則程序按照輸入的順序計(jì)算,最后輸出結(jié)果15?!境绦?.14】簡(jiǎn)易計(jì)算器。//Calculator.javapublicclassCalculator{ privateintstatus=0;//計(jì)算器當(dāng)前狀態(tài)

//0表示將已計(jì)算結(jié)果放入操作數(shù)1,等待運(yùn)算符,或重新輸入操作數(shù)

//1表示正在輸入操作數(shù)1 //2表示已輸入運(yùn)算符,等待輸入操作數(shù)2 //3表示正在輸入操作數(shù)2

privateStringnum1="0",num2="";//存儲(chǔ)運(yùn)算數(shù)

privatecharOp;//存儲(chǔ)運(yùn)算符

publicStringDisplayStr="0";//存儲(chǔ)運(yùn)算結(jié)果

//計(jì)算器回到初始狀態(tài)

publicvoidinit() { status=0; num1="0";

DisplayStr="0"; }

//處理一個(gè)按鍵

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; } }//計(jì)算結(jié)果

voidCal() { doublen1=newDouble(num1).doubleValue();//使用Double

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論