《Java程序設(shè)計教程》08 多線程與異常機(jī)制_第1頁
《Java程序設(shè)計教程》08 多線程與異常機(jī)制_第2頁
《Java程序設(shè)計教程》08 多線程與異常機(jī)制_第3頁
《Java程序設(shè)計教程》08 多線程與異常機(jī)制_第4頁
《Java程序設(shè)計教程》08 多線程與異常機(jī)制_第5頁
已閱讀5頁,還剩64頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

第8章多線程與異常機(jī)制本章學(xué)習(xí)目標(biāo)理解什么是多線程掌握線程的創(chuàng)建方法、生命期及狀態(tài)掌握線程的調(diào)度方法和優(yōu)先級設(shè)置方法了解線程組的概念及其實現(xiàn)方法熟悉異常機(jī)制8.1多線程概述進(jìn)程和線程單線程和多線程Java語言支持多線程說明進(jìn)程和線程進(jìn)程:一個動態(tài)執(zhí)行的程序。當(dāng)你運行一個程序的時候,就創(chuàng)建了一個用來容納組成代碼和數(shù)據(jù)空間的進(jìn)程。線程:進(jìn)程中單一順序的執(zhí)行流,線程可以共享內(nèi)存單元和系統(tǒng)資源,但不能夠單獨執(zhí)行,必須存在于某個進(jìn)程當(dāng)中。單線程和多線程單線程:一個進(jìn)程中只包含一個線程,也就是說一個程序只有一條執(zhí)行路線。多線程:在單個進(jìn)程中可以同時運行多個不同的線程執(zhí)行不同的任務(wù)。Java支持多線程Java線程由以下三部分組成:虛擬的CPUCPU所執(zhí)行的代碼CPU所處理的數(shù)據(jù)

虛擬的CPU被封裝在java.lang.Thread類中,有多少個線程就有多少個虛擬的CPU在同時運行,提供對多線程的支持。說明執(zhí)行多線程的時候,Java虛擬處理機(jī)在多個線程之間輪流切換,不過每個時刻只能有一個線程在執(zhí)行。main方法是Java的入口程序,一旦進(jìn)入就啟動了一個main線程。即使main方法執(zhí)行完最后一句,Java程序也會一直等到所有線程都運行結(jié)束后才停止。8.2多線程的創(chuàng)建線程體Thread子類創(chuàng)建線程使用Runnable接口創(chuàng)建線程比較線程體線程中真正執(zhí)行的語句塊稱為線程體。方法run()就是一個線程體,在一個線程被建立并初始化以后,系統(tǒng)就自動調(diào)用run()方法。8.2.1Thread子類創(chuàng)建線程繼承Thread類并重寫其中的方法run()來實現(xiàn),把線程實現(xiàn)的代碼寫到run()方法中,線程從run()方法開始執(zhí)行,直到執(zhí)行完最后一行代碼或線程消亡。請看例子8.2.2使用Runnable接口利用Runnable接口可以讓其他類的子類實現(xiàn)多線程的創(chuàng)建,這是利用繼承Thread類的方法無法辦到的。采用該方式來創(chuàng)建線程,還必須引用Thread類的構(gòu)造方法,把采用Runnable接口類的對象作為參數(shù)封裝到線程對象當(dāng)中。請看例子比較使用子類直接繼承Thread類的方法創(chuàng)建線程,可以在子類中增加新的成員變量和新的成員函數(shù),使得線程具有新的屬性和功能,還可以直接操作線程,但由于java中不支持多繼承,因此Thread子類不能擴(kuò)展其他的類;利用Runnable接口,線程的創(chuàng)建可以從其它類繼承,使得代碼和數(shù)據(jù)分開,不過需要使用Thread對象來操縱線程。8.3線程的生命期及其狀態(tài)線程的狀態(tài)線程的狀態(tài)轉(zhuǎn)換圖與線程狀態(tài)有關(guān)的Thread類方法8.3.1線程的狀態(tài)線程的生命期是指從線程被創(chuàng)建開始到死亡的過程。通常包括以下5種狀態(tài):新建狀態(tài)就緒狀態(tài)運行狀態(tài)阻塞狀態(tài)死亡狀態(tài)

新建狀態(tài)當(dāng)用Thread類或其子類創(chuàng)建了線程對象時,該線程對象就處于新建狀態(tài),系統(tǒng)為該新線程分配了內(nèi)存空間和其他資源。就緒狀態(tài)如果系統(tǒng)資源未滿足線程的調(diào)度,線程就開始排隊,等待CPU的時間片,此時,線程處于就緒狀態(tài)。有三種情況使得線程進(jìn)入就緒狀態(tài):

新建狀態(tài)的線程被啟動,但不具備運行的條件;處于正在運行的線程時間片結(jié)束或調(diào)用yield()方法;被阻塞的線程引起阻塞的因素消除了,進(jìn)入排隊隊列等待CPU的調(diào)度。運行狀態(tài)當(dāng)線程被調(diào)度獲得了CPU控制權(quán)的時候,就進(jìn)入了運行狀態(tài)。線程在運行狀態(tài)時,會調(diào)用本對象的run()方法。一般在子類中重寫父類的run()方法來實現(xiàn)多線程。阻塞狀態(tài)當(dāng)運行的線程被人為掛起或由于某些操作使得資源不滿足的時候,暫時終止自己的運行,讓出CPU,進(jìn)入阻塞狀態(tài)。有下面4種原因使得線程進(jìn)入阻塞狀態(tài):在線程運行過程中,調(diào)用了wait()方法,使得線程等待。等待中的線程并不會排隊等待CPU的調(diào)度,必須調(diào)用notify()通知方法,才能使它重新進(jìn)入排隊隊列等待CPU的時間片,也就是進(jìn)入就緒狀態(tài)。在線程運行過程中,調(diào)用了sleep(inttime)方法,使得線程休眠。休眠中的線程只有經(jīng)過休眠時間time之后,才會重新進(jìn)入排隊隊列等待CPU的調(diào)度,也就是進(jìn)入了就緒狀態(tài)。在線程運行過程中,調(diào)用了suspend()方法,使得線程掛起。掛起的線程需要調(diào)用resume()恢復(fù)方法,才能進(jìn)入就緒狀態(tài)。在線程運行過程中,由于輸入輸出流而引起阻塞。被阻塞的線程并不會排隊等待CPU的調(diào)度,只有引起阻塞的原因消除后,才能使它重新進(jìn)入排隊隊列等待CPU的時間片,也就是進(jìn)入就緒狀態(tài)。死亡狀態(tài)線程的run()方法執(zhí)行完所有的任務(wù)正常地結(jié)束;線程被stop()方法強(qiáng)制地終止。線程消亡有兩種情況:線程的狀態(tài)轉(zhuǎn)換圖8.3.2與線程狀態(tài)有關(guān)的Thread類方法線程狀態(tài)的判斷線程的新建和啟動線程的阻塞和喚醒線程的停止線程狀態(tài)的判斷isAlive()方法判斷線程是否在運行,如果是,返回true,否則返回false。不管是線程未開啟還是結(jié)束,isAlive()方法都會返回false。線程的新建和啟動通過newThread()方法可以創(chuàng)建出一個線程對象,不過此時Java虛擬機(jī)并不知道它,因此,我們需要通過start()方法來啟動它。請看例子線程的阻塞和喚醒wait()方法sleep()方法join()方法yield()方法suspend()方法wait()方法publicfinalvoidwait()publicfinalvoidwait(longtime)publicfinalvoidwait(longtime,intargs)調(diào)用wait()方法的線程必須通過調(diào)用notify()方法來喚醒它。方法定義如下:publicfinalvoidnotify()publicfinalvoidnotifyAll()其中,notify()方法是隨機(jī)喚醒一個等待的線程

notifyAll()方法是喚醒所有等待的線程。sleep()方法publicstaticvoidsleep(longtime)publicstaticvoidsleep(longtime,intargs)比較Thread的sleep()方法使線程進(jìn)入睡眠狀態(tài),但它并不會釋放線程持有的資源,不能被其他資源喚醒,不過睡眠一段時間會自動醒過來,而wait()方法讓線程進(jìn)入等待狀態(tài)的同時也釋放了持有的資源,能被其他資源喚醒。join()方法join()方法是指線程的聯(lián)合,即在一個線程運行過程中,若其他線程調(diào)用了join()方法與當(dāng)前運行的線程聯(lián)合,運行的線程會立刻阻塞,直到與它聯(lián)合的線程運行完畢后才重新進(jìn)入就緒狀態(tài),等待CPU的調(diào)度。publicfinalvoidjoin()publicfinalvoidjoin(longtime)publicfinalvoidjoin(longtime,intargs)請看例子yield()方法yield()方法是釋放當(dāng)前CPU的控制權(quán)。當(dāng)線程調(diào)用yield()方法的時候,若系統(tǒng)中存在相同優(yōu)先級的線程,線程將立刻停下調(diào)用其它優(yōu)先級相同的線程,若不存在相同優(yōu)先級的線程,那么yield()方法將不產(chǎn)生任何效果,當(dāng)前調(diào)用的線程將繼續(xù)運行。suspend()方法在Java2之前,可以利用suspend()和resume()方法對線程掛起和恢復(fù),但這兩個方法可能會導(dǎo)致死鎖,因此現(xiàn)在不提倡使用。Java語言建議采用wait()和notify()來代替suspend()和resume()方法。線程的停止使用stop()方法停止一個線程,不過stop()方法是不安全的,停止一個線程可能會使線程發(fā)生死鎖,所以現(xiàn)在不推薦使用了。Java建議使用其他的方法來代替stop()方法,比如可以把當(dāng)前線程對象設(shè)置為空,或者為線程類設(shè)置一個布爾標(biāo)志,定期地檢測該標(biāo)志是否為真,如要停止一個線程,就把該布爾標(biāo)志設(shè)置為true。請看例子8.4線程的同步示例Synchronized方法方法同步對象同步餓死和死鎖示例假設(shè)有兩個線程Thread1和Thread2同時要訪問變量num,線程Thread1對其進(jìn)行num=num+1的操作,線程Thread2是把num加一后的值附給一個變量data,而線程Thread1的加操作需要三步來執(zhí)行:把num裝入寄存器;對該寄存器加1;把寄存器內(nèi)容寫回num假設(shè)在第一步和第二步完成后該線程被切換,如果此時線程Thread2具有更高優(yōu)先級線程,線程Thread2占用了CPU,緊接著就把num值賦給data,雖然num的值已加1,但是還在寄存器中,于是出現(xiàn)了數(shù)據(jù)不一致性。為解決共享數(shù)據(jù)的操作問題,Java語言中引入線程同步的概念。Synchronized方法Java語言中使用關(guān)鍵字synchronized來實現(xiàn)線程的同步。當(dāng)一個方法或?qū)ο笫褂肧ynchronized關(guān)鍵字聲明的時候,系統(tǒng)就為其設(shè)置一特殊的內(nèi)部標(biāo)記,稱為鎖,當(dāng)一個線程調(diào)用該方法或?qū)ο蟮臅r候,系統(tǒng)都會檢查鎖是否已經(jīng)給其他線程了,如果沒有,系統(tǒng)就把該鎖給它,如果該鎖已經(jīng)被其他線程占用,那么該線程就要等到鎖被釋放了,才能訪問該方法。有時我們需要暫時釋放鎖,使得其他線程可以調(diào)用同步方法,這就可以利用wait()方法來實現(xiàn)。wait()方法可以使持有鎖的線程暫時釋放鎖,直到有其他線程通過notify方法使它重新獲得該鎖。8.4.1方法同步一個類中任何方法都可以設(shè)計成為synchronized方法。我們來看一個例子:

有兩個線程:Company和Staff,職員Staff有一個賬戶,公司每個月把工資存到該職員的賬戶上,該職員可以從賬戶上領(lǐng)取工資,職員每次要等Company線程把錢存到賬戶后,才能從賬戶上領(lǐng)取工資,這就涉及線程的同步機(jī)制。請看例子8.4.2對象同步synchronized除了像上面講的放在方法前面表示整個方法為同步方法外,還可以放在對象前面限制一段代碼的執(zhí)行,實現(xiàn)對象同步。請看例子另一種方法是使用Object對象來上鎖:請看例子8.4.3餓死和死鎖餓死:如果一個線程執(zhí)行很長時間,一直占著CPU資源,而使 得其它線程不能運行,就可能導(dǎo)致“餓死”。死鎖:如果兩個或多個線程都在互相等待對方持有的鎖,那么 這些線程都進(jìn)入阻塞狀態(tài),永遠(yuǎn)等待下去,無法執(zhí)行,程序就出現(xiàn)了死鎖。請看例子8.5線程的優(yōu)先級和調(diào)度線程的優(yōu)先級

線程的調(diào)度8.5.1線程的優(yōu)先級Java中,給每個線程賦一個從1到10整數(shù)值來表示多線程優(yōu)先級,優(yōu)先級決定了線程獲得CPU調(diào)度執(zhí)行的優(yōu)先程度。Thread.MIN_PRIORITY(通常為1)的優(yōu)先級最?。籘hread.MAX_PRIORITY(通常為10)優(yōu)先級最高,NORM_PRIORITY表示缺省優(yōu)先級,默認(rèn)值為5。優(yōu)先級的操作獲得線程的優(yōu)先級

intgetPriority();改變線程的優(yōu)先級

voidsetPriority(intnewPriority)請看例子8.5.2線程的調(diào)度Java調(diào)度器調(diào)度遵循以下原則:優(yōu)先級高的線程比優(yōu)先級低的線程線程先調(diào)度。優(yōu)先級相等的線程按照排隊隊列的順序進(jìn)行調(diào)度。先到隊列的線程先被調(diào)度。在時間片方式下,優(yōu)先級高的線程要等優(yōu)先級低的線程時間片運行完畢才能被調(diào)度。在搶占式調(diào)度方式下,優(yōu)先級高的線程可以立刻獲得CPU的控制權(quán)。由于優(yōu)先級低的線程只有等優(yōu)先級高的線程運行完畢或優(yōu)先級高的線程進(jìn)入阻塞狀態(tài)才有機(jī)會運行,為了讓優(yōu)先級低的線程也有機(jī)會運行,通常會不時讓優(yōu)先級高的線程進(jìn)入睡眠或等待狀態(tài),讓出CPU的控制權(quán)。8.6守護(hù)線程

setDaemon(booleanon)方法是把調(diào)用該方法的線程設(shè)置為守護(hù)線程。線程默認(rèn)為非守護(hù)線程,也就是用戶線程。當(dāng)我們把一個線程設(shè)置為守護(hù)線程時,守護(hù)線程在所有非守護(hù)線程運行完畢后它的run()方法還沒執(zhí)行結(jié)束,守護(hù)線程也會立刻結(jié)束。把一個線程設(shè)置為守護(hù)線程方式如下:

thread.setDaemon(true)請看例子8.7線程組入門

線程組的構(gòu)造ThreadGroup類的一些方法入門線程組是把多個線程集成到一個對象里并可以同時管理這些線程。每個線程組都擁有一個名字以及與它相關(guān)的一些屬性。每個線程都屬于一個線程組。在線程創(chuàng)建時,可以將線程放在某個指定的線程組中,也可以將它放在一個默認(rèn)的線程組。若創(chuàng)建線程而不明確指定屬于哪個組,它們就會自動歸屬于系統(tǒng)默認(rèn)的線程組。一旦線程加入了某個線程組,它將一直是這個線程組的成員,而不能改變到其他的組。線程組的構(gòu)造以下三種Thread類的構(gòu)造方法實現(xiàn)線程創(chuàng)建的同時指定其屬于哪個線程組。publicThread(ThreadGroupgroup,Runnabletarget)publicThread(ThreadGroupgroup,Stringname)publicThread(ThreadGroupgroup,Runnabletarget,Stringname)ThreadGroup類的一些方法activeCount() //返回線程組中當(dāng)前所有激活的線程的數(shù)目。activeGroupCount()//返回當(dāng)前激活的線程作為父線的線程組的數(shù)目。getName() //返回線程組的名字。getParent()//返回該線程的父線程組的名稱。setMaxPriority(intpriority)//設(shè)置線程組的最高優(yōu)先級。getMaxPriority()//獲得線程組包含的線程中的最高優(yōu)先級。getThreadGroup()//返回線程組。isDestroyed()//判斷線程組是否已經(jīng)被銷毀。destroy() //銷毀線程組及其它包含的所有線程。interrupt()//向線程組及其子組中的線程發(fā)送一個中斷信息。parentOf(ThreadGroupgroup)//判斷線程組是否是線程組group或其子線程組。setDaemon(booleamdaemon)//將該線程組設(shè)置為守護(hù)狀態(tài)。isDaemon()//判斷是否是守護(hù)線程組。ThreadGroup類的一些方法list()//顯示當(dāng)前線程組的信息。toString()//返回一個表示本線程組的字符串。enumerate(Thread[]list)//將當(dāng)前線程組中所有的線程復(fù)制到list數(shù)組中。enumerate(Thread[]list,booleanargs) //將當(dāng)前線程組中所有的線程復(fù)制到list數(shù)組中,若args為true,則把所有子線程組中的線程復(fù)制到list數(shù)組中。enumerate(ThreadGroup[]group) //將當(dāng)前線程組中所有的子線程組復(fù)制到group數(shù)組中。enumerate(ThreadGroup[]group,booleanargs) //將當(dāng)前線程組中所有的子線程組復(fù)制到group數(shù)組中,若args為true,則把所有子線程組中的子線程組復(fù)制到group數(shù)組中。請看例子8.8異常機(jī)制

在Java語言中,將程序編譯或執(zhí)行中發(fā)生的不正常情況稱為“異?!?。異??煞譃榫幾g時異常和運行時異常。Java定義了異常類Exception,然后由它派生出RuntimeException、IOException(FileNotFoundException為其子類異常類)、ReflectiveOperationException(ClassNotFoundException為其子類異常類)和SQLException等,RuntimeException為運行時異常,其他如IOException和SQLException等為checked異常,即編譯時要檢查的異常。

8.8.1異常示例【例8-11】編譯時異常。importjava.io.*;publicclassTestIOException{publicstaticvoidmain(String[]args)//throwsIOException{ charsex; System.out.println("請輸入性別代號:");sex=(char)System.in.read();if(sex!='u'){if(sex=='m')System.out.println("男性");if(sex=='f')System.out.println("女性");}elseSystem.out.println("未知");}}上述程序編譯報錯如下:

c:\工作目錄>javacTestIOException.java

TestIOException.java:6:錯誤:未報告的異常錯誤IOException;必須對其進(jìn)行捕獲或聲明以便拋出sex=(char)System.in.read();^上面6表示是代碼第6行System.in.read()方法引發(fā)的異常,異常類型為IOException,編譯系統(tǒng)提示:必須對其進(jìn)行捕獲或聲明以便拋出。上述代碼中將注釋//去掉,拋出該異常,編譯便成功。又比如第10章將介紹的Java輸入輸出中,【例10-6】有如下一行代碼:

FileInputStreamfis=newFileInputStream("data.dat");newFileInputStream("data.dat")可能會由于文件data.dat路徑不對或名稱不對,而引發(fā)FileNotFoundException,若未對其進(jìn)行該異常捕獲或拋出聲明,則編譯將失敗。此外,初學(xué)者在編譯程序時,也常會遇到ClassNotFoundException的編譯時異常,這種情況,往往是由于環(huán)境變量classpath的路徑設(shè)置漏了或設(shè)置不對以及包名(包目錄)可能有誤而引發(fā),讀者注意Check下,確保編譯系統(tǒng)編譯時能找到相應(yīng)的類,問題就解決了。下面看幾個運行時異常的例子:publicvoidRunTimeE1(){shortx[]=newshort[6];System.out.println(x[7]);//引發(fā)ArrayIndexOutOfBoundsException數(shù)組下標(biāo)越界異常}publicvoidRunTimeE2(){Stringstr="ok";

inti=Integer.parseInt(str);//引發(fā)NumberFormatException數(shù)字格式異常}publicvoidRunTimeE3(){char[]s=null;

System.out.println(s[1]);//引發(fā)NullPointerException空指針異常,即空引用}publicvoidRunTimeE4(){inti=10;

intj=0;

intk=i/j;//引發(fā)ArithmeticException算數(shù)異常,即除0異常}8.8.2異常拋出和處理【例8-11】通過拋出異常throwsIOException的聲明解決了其編譯時異常問題。異常拋出:throws和throw異常處理:try-catch-finally異常拋出:throws和throw

1)throws出現(xiàn)在方法的聲明中,表示該方法中的代碼可能會引發(fā)異常,故將其拋出,交給上層調(diào)用它的方法處的程序進(jìn)行處理,若該方法調(diào)用處也沒有處理,則須繼續(xù)向上拋出,直至得到處理,若一直到main方法中也得不到處理,則須在main方法聲明處將其繼續(xù)拋出,拋給JVM(JavaVirtualMachine,Java虛擬機(jī),即Java[運行時]系統(tǒng))進(jìn)行默認(rèn)處理,也就是拋給Java系統(tǒng)內(nèi)置的異常機(jī)制進(jìn)行處理,此時用戶程序?qū)⒈恢袛嗤顺?,JVM系統(tǒng)會給出相應(yīng)異常信息提示,指導(dǎo)用戶對程序進(jìn)行糾錯,將異??刂圃谟脩舫绦騼?nèi)進(jìn)行處理,避免程序異常退出。比如【例8-11】中,main方法就被Java編譯系統(tǒng)強(qiáng)制要求拋出IOException,因為main方法中調(diào)用了庫類的System.in.read()方法,而該方法,Java系統(tǒng)規(guī)定:必須對其進(jìn)行捕獲處理或聲明以便拋出。Java允許throws聲明后面跟著多個異常類型,多個異常類型間以逗號間隔開,throws聲明位于方法聲明的尾部。

為什么【例8-11】沒有進(jìn)行異常捕獲處理呢?這是因為它的代碼簡單,用戶任意輸入,都不會引發(fā)異常,假如它的代碼復(fù)雜,在System.in.read()方法被調(diào)用前,出于某種需要,System.in.close()方法被調(diào)用了,即in這個輸入流對象被關(guān)閉,則此時將引發(fā)IOException,這種情況下,為了避免程序異常退出,就必須對其進(jìn)行捕獲處理,而不僅僅是拋給JVM系統(tǒng)去處理了。

2)throws是異常的拋出聲明,而throw則是拋出異常,即引發(fā)異常,引發(fā)異常有兩種,一種是程序代碼問題被動引發(fā)異常,一種是throw語句主動(拋出)引發(fā)異常。throw只會出現(xiàn)在方法體中,當(dāng)方法在執(zhí)行過程中遇到異常情況時,主動生成異常對象,然后throw出去,讓本方法或上(上)層調(diào)用它的方法通過try-catch語句進(jìn)行捕獲處理。throw常用于程序出現(xiàn)某種邏輯錯誤時程序員主動拋出某種特定類型的異常,即程序員用戶的自定義異常類。

throws聲明表示本方法體內(nèi)的代碼有可能會引發(fā)異常;throw則是拋出(引發(fā))了異常,執(zhí)行throw語句一定引發(fā)異常,因為它生成并拋出了某種異常對象。異常處理:try-catch-finallytry{…//可能出現(xiàn)異常的代碼}catch(XExceptione){…//處理XException的代碼}catch(YExceptione){…//處理YException的代碼}catch(ZExceptione){…//處理ZException的代碼}…finally{…//一定會執(zhí)行的代碼}1)finally是可選的。2)使用try將可能會出現(xiàn)異常的代碼段包裝起來,在執(zhí)行過程中,一旦出現(xiàn)異常,就會生成一個對應(yīng)異常類的對象,根據(jù)此對象的類型,去catch中進(jìn)行匹配。3)一旦try中的異常對象匹配到某一個catch時,就進(jìn)入catch中進(jìn)行異常的處理。一旦處理完成,就跳出當(dāng)前的try-catch結(jié)構(gòu)(在沒有寫finally的情況)。繼續(xù)執(zhí)行其后的代碼。4)catch中的異常類型如果沒有父子類關(guān)系,則誰聲明在上,誰聲明在下無所謂。catch中的異常類型如果滿足父子類關(guān)系,則要求子類一定聲明在父類的上面。否則,報錯。5)finally中編寫的代碼一定會被執(zhí)行,主要用于將try中生成的資源對象進(jìn)行釋放,如輸入輸出流、數(shù)據(jù)庫連接等。6)程序繼續(xù)執(zhí)行。有了try-catch-finally異常處理的保護(hù),代碼的健壯性得以增強(qiáng),避免了代碼異常導(dǎo)致的程序中斷退出?!纠?-12】前面幾個運行時異常的異常處理。程序在JDK17下編譯成功,運行如下所示:c:\工作目錄>javaProcessRunTimeExceptions數(shù)組下標(biāo)越界異常:Index7outofboundsforlength6數(shù)字格式異常:Forinputstring:"ok"空指針異常:Cannotloadfromchararraybecause"<local3>"isnull算數(shù)異常即除0異常:/byzero上述幾個運行時異常都被處理了,程序不會異常退出!異常處理成功,程序繼續(xù)執(zhí)行...上面幾個異常,只要有一個沒被處理,程序?qū)⒃谝l(fā)異常處即中斷退出。然而,運行時異常在實際編程過程中,往往會由于程序員的疏忽或者程序規(guī)模較大較難掌控而引發(fā),對于程序運行一次就會引發(fā)的異常,程序員可以立刻查找原因,對引發(fā)異常的代碼進(jìn)行異常處理,而對于其他一些異常,可能要運行多次,才會發(fā)現(xiàn)有異常,因此,程序員在交付程序前,務(wù)必要多測試幾次,關(guān)于軟件測試,也是一門學(xué)問,將來,大家如果參與實際項目開發(fā)了,就會體會到。【例8-13】主動拋出異常并進(jìn)行異常處理。publicclassLoginException{publicstaticvoidlogin(Stringuser,Stringpwd){if(user==null||pwd==null)thrownewNullPointerException("用戶名或者密碼為空");//主動拋出異常//...}publicstaticvoidmain(String[]args){try{Stringuser=null;Stringpwd=null;login(user,pwd);}catch(Exceptione){System.out.println(e.getMessage());//getMessage獲得的信息見運行輸出}}}程序編譯、運行輸出如下:c:\工作目錄>javaLoginException用戶名或者密碼為空8.8.3異常類Java類庫自帶定義了很多異常類,它們的根類是Throwable,如下圖所示:1.庫類異常類Java庫類中的異常類根類是Throwable,由它派生出了兩個子類:Exception類和Error類。Throwable類提供了三個非常有用的方法:(1)StringgetMessage():獲取異常的描述信息;(2)StringtoString():獲取異常的類型、異常描述信息;(3)voidprintStackTrace():打印異常的跟蹤棧信息并輸出到控制臺,但不能在System.out.println()中使用該方法;其中包含了異常的類型、異常的原因、異常出現(xiàn)的位置;在開發(fā)和調(diào)試階段,該方法很有用,方便調(diào)試和修改;由于Throwable是根類,它的子類Exception類和Error類及它們再派生出的所有子類,都繼承了該方法?!纠?-15】Throwable類的三個常用方法。publicclassProcessRunTimeExceptions1{publicstaticvoidmain(String[]args){shortx[]=newshort[6];try{System.out.println(x[7]);}catch(ArrayIndexOutOfBoundsExceptione){System.out.println(e.getMessage());System.out.println(e.toString());System.out.println("異常棧追蹤:");e.printStackTrace();}}}編譯,運行如下:c:\工作目錄>javaProcessRunTimeExceptions1Index7outofboundsforlength6//e.getMessage();java.lang.ArrayIndexOutOfBoundsException:Index7outofboundsforlength6//e.toString();異常棧追蹤://下面是e.printStackTrace();java.lang.ArrayIndexOutOfBoundsException:Index7outofboundsforlength6atProcessRunTimeExceptions1.main(ProcessRunTimeExceptions1.java:5)//5是代碼出錯行Error類及其子類屬于系統(tǒng)錯誤,不能通過try-catch異常處理加以解決,它們是Java虛擬機(jī)也無法解決的,如JVM系統(tǒng)內(nèi)部錯誤、資源耗盡等嚴(yán)重錯誤,Error子類VirtualMachineError又派生了StackOverflowError和OutOfMemoryError等子類錯誤。【例8-16】StackOverflowError示例。publicclassStackOverflowErrorExample{publicstaticvoidmain(String[]args){

//棧溢出錯誤:java.lang.StackOverflowErrormain(args);//無限遞歸導(dǎo)致}}編譯成功,但運行如下:c:\工作目錄>javaStackOverflowErrorExampleExceptioninthread"main"java.lang.StackOverflowErroratStackOverflowErrorExample.main(StackOverflowErrorExample.java:4)//4是代碼出錯行atStackOverflowErrorExample.main(StackOverflowErrorExample.java:4)atStackOverflowErrorExample.main(StackOverflowErrorExample.java:4)…………c:\工作目錄

溫馨提示

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

最新文檔

評論

0/150

提交評論