凡科建站的怎么取消手機(jī)網(wǎng)站怎樣建立自己的網(wǎng)站平臺(tái)
Java基礎(chǔ)06-異常機(jī)制
異常概念
在我們?nèi)粘I钪?有時(shí)會(huì)出現(xiàn)各種各樣的異常,例如:職工小王開(kāi)車(chē)去上班,在正常情況下,小王會(huì)準(zhǔn)時(shí)到達(dá)單位。但是天有不測(cè)風(fēng)云,在小王去上班時(shí),可能會(huì)遇到一些異常情況,比如小王的車(chē)子出了故障,小王只能 改為步行.
實(shí)際工作中,遇到的情況不可能是非常完美的。比如:你寫(xiě)的某個(gè)模塊,用戶(hù)輸入不一定符合你的要 求、你的程序要打開(kāi)某個(gè)文件,這個(gè)文件可能不存在或者文件格式不對(duì),你要讀取數(shù)據(jù)庫(kù)的數(shù)據(jù),數(shù)據(jù) 可能是空的等。我們的程序再跑著,內(nèi)存或硬盤(pán)可能滿(mǎn)了。等等。
軟件程序在運(yùn)行過(guò)程中,非??赡苡龅絼倓偺岬降倪@些異常問(wèn)題,我們叫異常,英文是:Exception, 意思是例外。這些,例外情況,或者叫異常,怎么讓我們寫(xiě)的程序做出合理的處理。而不至于程序崩 潰。
異常指程序運(yùn)行中出現(xiàn)的不期而至的各種狀況,如:文件找不到、網(wǎng)絡(luò)連接失敗、非法參數(shù)等。異常發(fā)生在程序運(yùn)行期間,它影響了正常的程序執(zhí)行流程。
比如說(shuō),你的代碼少了一個(gè)分號(hào),那么運(yùn)行出來(lái)結(jié)果是提示是錯(cuò)誤java.lang.Error;如果你用 System.out.println(11/0) ,那么你是因?yàn)槟阌?做了除數(shù),會(huì)拋出的異常java.lang.ArithmeticException 。
異常發(fā)生的原因有很多,通常包含以下幾大類(lèi):
-
用戶(hù)輸入了非法數(shù)據(jù)。
-
要打開(kāi)的文件不存在。
-
網(wǎng)絡(luò)通信時(shí)連接中斷,或者JVM內(nèi)存溢出。
這些異常有的是因?yàn)橛脩?hù)錯(cuò)誤引起,有的是程序錯(cuò)誤引起的,還有其它一些是因?yàn)槲锢礤e(cuò)誤引起的。 要理解Java異常處理是如何工作的,你需要掌握以下三種類(lèi)型的異常:
-
**檢查性異常:**最具代表的檢查性異常是用戶(hù)錯(cuò)誤或問(wèn)題引起的異常,這是程序員無(wú)法預(yù)見(jiàn)的。例如 要打開(kāi)一個(gè)不存在文件時(shí),一個(gè)異常就發(fā)生了,這些異常在編譯時(shí)不能被簡(jiǎn)單地忽略。
-
運(yùn)行時(shí)異常: 運(yùn)行時(shí)異常是可能被程序員避免的異常。與檢查性異常相反,運(yùn)行時(shí)異??梢栽诰幾g時(shí)被忽略。
-
錯(cuò)誤: 錯(cuò)誤不是異常,而是脫離程序員控制的問(wèn)題。錯(cuò)誤在代碼中通常被忽略。例如,當(dāng)棧溢出時(shí),一個(gè)錯(cuò)誤就發(fā)生了,它們?cè)诰幾g也檢查不到的。
? 異常指不期而至的各種狀況,如:文件找不到、網(wǎng)絡(luò)連接失敗、除0操作、非法參數(shù)等。異常是一個(gè) 事件,它發(fā)生在程序運(yùn)行期間,干擾了正常的指令流程。
? Java語(yǔ)言在設(shè)計(jì)的當(dāng)初就考慮到這些問(wèn)題,提出異常處理的框架的方案,所有的異常都可以用一個(gè) 異常類(lèi)來(lái)表示,不同類(lèi)型的異常對(duì)應(yīng)不同的子類(lèi)異常(目前我們所說(shuō)的異常包括錯(cuò)誤概念),定義異常處理的規(guī)范,在JDK1.4 版本以后增加了異常鏈機(jī)制,從而便于跟蹤異常。
? Java異常是一個(gè)描述在代碼段中發(fā)生異常的對(duì)象,當(dāng)發(fā)生異常情況時(shí),一個(gè)代表該異常的對(duì)象被創(chuàng) 建并且在導(dǎo)致該異常的方法中被拋出,而該方法可以選擇自己處理異?;蛘邆鬟f該異常。
異常體系結(jié)構(gòu)
Java把異常當(dāng)作對(duì)象來(lái)處理,并定義一個(gè)基類(lèi) java.lang.Throwable 作為所有異常的超類(lèi)。
在Java API中已經(jīng)定義了許多異常類(lèi),這些異常類(lèi)分為兩大類(lèi),錯(cuò)誤Error和異常Exception。
Java異常層次結(jié)構(gòu)圖:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-dVsbjQUh-1657115739280)(C:\Users\chene\AppData\Roaming\Typora\typora-user-images\image-20220706202047442.png)]
從圖中可以看出所有異常類(lèi)型都是內(nèi)置類(lèi)Throwable 的子類(lèi),因而Throwable 在異常類(lèi)的層次結(jié)構(gòu)的頂層。
? 接下來(lái)Throwable分成了兩個(gè)不同的分支,一個(gè)分支是Error,它表示不希望被程序捕獲或者是程序無(wú)法處理的錯(cuò)誤。另一個(gè)分支是Exception,它表示用戶(hù)程序可能捕捉的異常情況或者說(shuō)是程序可以處 理的異常。
? 其中異常類(lèi) Exception 又分為運(yùn)行時(shí)異常( RuntimeException ) 和非運(yùn)行時(shí)異常。Java異常又可以分為不受檢查異常(Unchecked Exception) 和檢查異常(checked Exception) 。
?
異常之間的區(qū)別與聯(lián)系
1、Error
Error類(lèi)對(duì)象由 Java 虛擬機(jī)生成并拋出,大多數(shù)錯(cuò)誤與代碼編寫(xiě)者所執(zhí)行的操作無(wú)關(guān)。
比如說(shuō):
? Java虛擬機(jī)運(yùn)行錯(cuò)誤(Virtual MachineError),當(dāng)JVM不再有繼續(xù)執(zhí)行操作所需的內(nèi)存資源時(shí),將出現(xiàn) OutOfMemoryError 。這些異常發(fā)生時(shí),Java虛擬機(jī)(JVM)一般會(huì)選擇線(xiàn)程終止;還有發(fā)生在虛擬機(jī)試圖執(zhí)行應(yīng)用時(shí),如類(lèi)定義(NoClassDefFoundError)、鏈接錯(cuò)誤( LinkageError)。這些錯(cuò)誤是不可查的,因?yàn)樗鼈冊(cè)趹?yīng)用程序的控制和處理能力之 外,而且絕大多數(shù)是程序運(yùn)行時(shí)不允許出現(xiàn)的狀況。
對(duì)于設(shè)計(jì)合理的應(yīng)用程序來(lái)說(shuō),即使確實(shí)發(fā)生了錯(cuò)誤,本質(zhì)上也不應(yīng)該試圖去處理它所引起的異常狀況。在Java中,錯(cuò)誤通常是使用Error的子類(lèi)描述。
2、Exception
? 在 Exception 分支中有一個(gè)重要的子類(lèi) RuntimeException (運(yùn)行時(shí)異常),該類(lèi)型的異常自動(dòng)為你所編寫(xiě)的程序定義ArrayIndexOutOfBoundsException (數(shù)組下標(biāo)越界)、 NullPointerException(空指針異常)、ArithmeticException(算術(shù)異常)、MissingResourceException(丟失資源)、ClassNotFoundException 找不到類(lèi))等異常,這些異常是不檢查異常,程序中可以選擇捕獲處理,也可以不處理。
? 這些異常一般是由程序邏輯錯(cuò)誤引起的,程序應(yīng)該從邏輯角度盡可能避免這類(lèi)異常的發(fā)生;而RuntimeException 之外的異常我們統(tǒng)稱(chēng)為非運(yùn)行時(shí)異常,類(lèi)型上屬于Exception類(lèi)及其子類(lèi),
? 從程序語(yǔ)法角度講是必須進(jìn)行處理的異常,如果不處理,程序就不能編譯通過(guò)。如IOException,SQLException等以及用戶(hù)自定義的
Exception異常,一般情況下不自定義檢查異常。
? 注意:Error和Exception的區(qū)別:的區(qū)別:通常是災(zāi)難性的致命的錯(cuò)誤,是程序無(wú)法控制和處理的,當(dāng)出現(xiàn)這些異常時(shí),Java虛擬機(jī)(JVM)一般會(huì)選擇終止線(xiàn)程;Exception通常情況下是可以被程序處理的,并且在程序中應(yīng)該盡可能的去處理這些異常。
3、檢查異常和不受檢查異常
檢查異常:在正確的程序運(yùn)行過(guò)程中,很容易出現(xiàn)的、情理可容的異常狀況,在一定程度上這種異常的 發(fā)生是可以預(yù)測(cè)的,并且一旦發(fā)生該種異常,就必須采取某種方式進(jìn)行處理。
解析:除了RuntimeException及其子類(lèi)以外,其他的Exception類(lèi)及其子類(lèi)都屬于檢查異常,當(dāng)程序 中可能出現(xiàn)這類(lèi)異常,要么使用try-catch語(yǔ)句進(jìn)行捕獲,要么用throws子句拋出,否則編譯無(wú)法通過(guò)。
不受檢查異常:包括RuntimeException及其子類(lèi)和Error。
分析: 不受檢查異常 為編譯器不要求強(qiáng)制處理的異常,檢查異常 則是編譯器要求必須處置的異
Java異常處理機(jī)制
java異常處理本質(zhì):拋出異常和捕獲異常
1、拋出異常
要理解拋出異常,首先要明白什么是異常情形(exception condition),它是指阻止當(dāng)前方法或作用域繼續(xù)執(zhí)行的問(wèn)題。其次把異常情形和普通問(wèn)題相區(qū)分,普通問(wèn)題是指在當(dāng)前環(huán)境下能得到足夠的信息, 總能處理這個(gè)錯(cuò)誤。
對(duì)于異常情形,已經(jīng)無(wú)法繼續(xù)下去了,因?yàn)樵诋?dāng)前環(huán)境下無(wú)法獲得必要的信息來(lái)解決問(wèn)題,你所能做的 就是從當(dāng)前環(huán)境中跳出,并把問(wèn)題提交給上一級(jí)環(huán)境,這就是拋出異常時(shí)所發(fā)生的事情。拋出異常后, 會(huì)有幾件事隨之發(fā)生。
首先,是像創(chuàng)建普通的java對(duì)象一樣將使用 new 在堆上創(chuàng)建一個(gè)異常對(duì)象;然后,當(dāng)前的執(zhí)行路徑(已經(jīng)無(wú)法繼續(xù)下去了)被終止,并且從當(dāng)前環(huán)境中彈出對(duì)異常對(duì)象的引用。此時(shí),異常處理機(jī)制接管 程序,并開(kāi)始尋找一個(gè)恰當(dāng)?shù)牡胤嚼^續(xù)執(zhí)行程序,
這個(gè)恰當(dāng)?shù)牡胤骄褪钱惓L幚沓绦蚧蛘弋惓L幚砥?#xff0c;它的任務(wù)是將程序從錯(cuò)誤狀態(tài)中恢復(fù),以使程序要 么換一種方式運(yùn)行,要么繼續(xù)運(yùn)行下去。
舉例:
假使我們創(chuàng)建了一個(gè)學(xué)生對(duì)象Student的一個(gè)引用stu,在調(diào)用的時(shí)候可能還沒(méi)有初始化。所以在使用這個(gè) 對(duì)象引用調(diào)用其他方法之前,要先對(duì)它進(jìn)行檢查,可以創(chuàng)建一個(gè)代表錯(cuò)誤信息的對(duì)象,并且將它從當(dāng)前 環(huán)境中拋出,這樣就把錯(cuò)誤信息傳播到更大的環(huán)境中。
if(stu == null){throw new NullPointerException();
}
2、捕獲異常
在方法拋出異常之后,運(yùn)行時(shí)系統(tǒng)將轉(zhuǎn)為尋找合適的異常處理器(exception handler)。潛在的異常處理器是異常發(fā)生時(shí)依次存留在調(diào)用棧中的方法的集合。當(dāng)異常處理器所能處理的異常類(lèi)型與方法拋出 的異常類(lèi)型相符時(shí),即為合適的異常處理器。運(yùn)行時(shí)系統(tǒng)從發(fā)生異常的方法開(kāi)始,依次回查調(diào)用棧中的 方法,直至找到含有合適異常處理器的方法并執(zhí)行。當(dāng)運(yùn)行時(shí)系統(tǒng)遍歷調(diào)用棧而未找到合適的異常處理 器,則運(yùn)行時(shí)系統(tǒng)終止。同時(shí),意味著Java程序的終止。
注意:
對(duì)于運(yùn)行時(shí)異常 、錯(cuò)誤 和檢查異常 ,Java技術(shù)所要求的異常處理方式有所不同
由于運(yùn)行時(shí)異常及其子類(lèi)的不可查性,為了更合理、更容易地實(shí)現(xiàn)應(yīng)用程序,Java規(guī)定,運(yùn)行時(shí)異常將 由Java運(yùn)行時(shí)系統(tǒng)自動(dòng)拋出,允許應(yīng)用程序忽略運(yùn)行時(shí)異常。
對(duì)于方法運(yùn)行中可能出現(xiàn)的 Error ,當(dāng)運(yùn)行方法不欲捕捉時(shí),Java允許該方法不做任何拋出聲明。因
)為,大多數(shù) Error 異常屬于永遠(yuǎn)不能被允許發(fā)生的狀況,也屬于合理的應(yīng)用程序不該捕捉的異常。
對(duì)于所有的檢查異常,Java規(guī)定:一個(gè)方法必須捕捉,或者聲明拋出方法之外。也就是說(shuō),當(dāng)一個(gè)方法 選擇不捕捉檢查異常時(shí),它必須聲明將拋出異常。
3、異常處理五個(gè)關(guān)鍵字
分別是: 、 、 、 、
try – 用于監(jiān)聽(tīng)。將要被監(jiān)聽(tīng)的代碼(可能拋出異常的代碼)放在try語(yǔ)句塊之內(nèi),當(dāng)try語(yǔ)句塊內(nèi)發(fā)生異常時(shí),異常就被拋出。
catch – 用于捕獲異常。catch用來(lái)捕獲try語(yǔ)句塊中發(fā)生的異常。
?nally – ?nally語(yǔ)句塊總是會(huì)被執(zhí)行。它主要用于回收在try塊里打開(kāi)的物力資源(如數(shù)據(jù)庫(kù)連接、網(wǎng)絡(luò)連接和磁盤(pán)文件)。只有?nally塊,執(zhí)行完成之后,才會(huì)回來(lái)執(zhí)行try或者catch塊中的return或者throw語(yǔ)句,如果?nally中使用了return或者throw等終止方法的語(yǔ)句,則就不會(huì)跳回執(zhí)行,直接停止。
throw – 用于拋出異常。
throws – 用在方法簽名中,用于聲明該方法可能拋出的異常。
處理異常
1、try -catch
try{//code that might generate exceptions}catch(Exception e){//the code of handling exception1}catch(Exception e){//the code of handling exception2}
要明白異常捕獲,還要理解 監(jiān)控區(qū)域 (guarded region)的概念。它是一段可能產(chǎn)生異常的代碼, 并且后面跟著處理這些異常的代碼。
因而可知,上述 try-catch 所描述的即是監(jiān)控區(qū)域,關(guān)鍵詞 try 后的一對(duì)大括號(hào)將一塊可能發(fā)生異常的代碼包起來(lái),即為監(jiān)控區(qū)域。Java方法在運(yùn)行過(guò)程中發(fā)生了異常,則創(chuàng)建異常對(duì)象。
將異常拋出監(jiān)控區(qū)域之外,由Java運(yùn)行時(shí)系統(tǒng)負(fù)責(zé)尋找匹配的 catch 子句來(lái)捕獲異常。若有一個(gè) catch 語(yǔ)句匹配到了,則執(zhí)行該 catch
塊中的異常處理代碼,就不再?lài)L試匹配別的 catch 塊了。
匹配原則:如果拋出的異常對(duì)象屬于 catch 子句的異常類(lèi),或者屬于該異常類(lèi)的子類(lèi),則認(rèn)為生成的異常對(duì)象與 catch 塊捕獲的異常類(lèi)型相匹配。
【演示】
public class TestException {public static void main(String[] args) {int a = 1;int b = 0;try { // try監(jiān)控區(qū)域if (b == 0) throw new ArithmeticException(); // 通過(guò)throw語(yǔ)句拋出異常System.out.println("a/b的值是:" + a / b);System.out.println("this will not be printed!");}catch (ArithmeticException e) { // catch捕捉異常System.out.println("程序出現(xiàn)異常,變量b不能為0!");}System.out.println("程序正常結(jié)束。");}
}//輸出
程序出現(xiàn)異常,變量b不能為0!
程序正常結(jié)束。
**注意:**顯示一個(gè)異常的描述,Throwable 重載了toString() 方法(由Object 定義),所以它將返回一個(gè)包含異常描述的字符串。例如,將前面的 catch 塊重寫(xiě)成:
catch (ArithmeticException e) { // catch捕捉異常ystem.out.println("程序出現(xiàn)異常"+e);
}
//輸出
程序出現(xiàn)異常java.lang.ArithmeticException
程序正常結(jié)束。
算術(shù)異常屬于運(yùn)行時(shí)異常,因而實(shí)際上該異常不需要程序拋出,運(yùn)行時(shí)系統(tǒng)自動(dòng)拋出。如果不用try- catch程序就不會(huì)往下執(zhí)行了。
【演示】
public class TestException {public static void main(String[] args) {int a = 1;int b = 0;System.out.println("a/b的值是:" + a / b);System.out.println("this will not be printed!");}
}結(jié)果:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at TestException.main(TestException.java:7)
使用多重的catch語(yǔ)句:很多情況下,由單個(gè)的代碼段可能引起多個(gè)異常。處理這種情況,我們需要定義兩個(gè)或者更多的 catch 子句,每個(gè)子句捕獲一種類(lèi)型的異常,當(dāng)異常被引發(fā)時(shí),每個(gè) catch 子句被依次檢查,第一個(gè)匹配異常類(lèi)型的子句執(zhí)行,當(dāng)一個(gè) catch 子句執(zhí)行以后,其他的子句將被旁路。
編寫(xiě)多重catch語(yǔ)句塊注意事項(xiàng):
順序問(wèn)題:先小后大,即先子類(lèi)后父類(lèi)
注意:
Java通過(guò)異常類(lèi)描述異常類(lèi)型。對(duì)于有多個(gè)catch 子句的異常程序而言,應(yīng)該盡量將捕獲底層異常類(lèi)
的 catch 子句放在前面,同時(shí)盡量將捕獲相對(duì)高層的異常類(lèi)的catch 子句放在后面。否則,捕獲
底層異常類(lèi)的catch 子句將可能會(huì)被屏蔽。
嵌套try語(yǔ)句: try語(yǔ)句可以被嵌套。也就是說(shuō),一個(gè) try 語(yǔ)句可以在另一個(gè) try塊的內(nèi)部。每次進(jìn)入 try語(yǔ)句,異常的前后關(guān)系都會(huì)被推入堆棧。如果一個(gè)內(nèi)部的 try 語(yǔ)句不含特殊異常的catch 處理程序,堆棧將彈出,下一個(gè) try語(yǔ)句的 catch 處理程序?qū)z查是否與之匹配。這個(gè)過(guò)程將繼續(xù)直到一個(gè) catch 語(yǔ)句被匹配成功,或者是直到所有的嵌套 try語(yǔ)句被檢查完畢。如果沒(méi)有 catch 語(yǔ)句匹配,Java運(yùn)行時(shí)系統(tǒng)將處理這個(gè)異常。
【演示】
class NestTry{public static void main(String[] args){try{int a = args.length;int b = 42 / a;System.out.println("a = "+ a);try{if(a == 1){a = a/(a-a);}if(a == 2){int c[] = {1};c[42] =99;}}catch(ArrayIndexOutOfBoundsException e){System.out.println("ArrayIndexOutOfBounds :"+e); }}catch(ArithmeticException e){System.out.println("Divide by 0"+ e); }}}//分析運(yùn)行:
D:\java>java NestTry onea = 1Divide by 0java.lang.ArithmeticException: / by zeroD:\java>java NestTry one twoa = 2ArrayIndexOutOfBounds :java.lang.ArrayIndexOutOfBoundsException: 42
分析:正如程序中所顯示的,該程序在一個(gè) try 塊中嵌套了另一個(gè) try 塊。程序工作如下:當(dāng)你在沒(méi)
有命令行參數(shù)的情況下執(zhí)行該程序,外面的 try 塊將產(chǎn)生一個(gè)被0除的異常。
程序在有一個(gè)命令行參數(shù)條件下執(zhí)行,由嵌套的 try 塊產(chǎn)生一個(gè)被0除的異常,由于內(nèi)部的catch
塊不匹配這個(gè)異常,它將把異常傳給外部的 try 塊,在外部異常被處理。如果你在具有兩個(gè)命令行參
數(shù)的條件下執(zhí)行該程序,將由內(nèi)部 try 塊產(chǎn)生一個(gè)數(shù)組邊界異常。
注意:當(dāng)有方法調(diào)用時(shí), try 語(yǔ)句的嵌套可以很隱蔽的發(fā)生。例如,我們可以將對(duì)方法的調(diào)用放在一
個(gè) try 塊中。在該方法的內(nèi)部,有另一個(gè) try 語(yǔ)句。
在這種情況下,方法內(nèi)部的 try 仍然是嵌套在外部調(diào)用該方法的 try 塊中的。下面我們將對(duì)上述例子進(jìn)行修改,嵌套的 try 塊移到方法nesttry()的內(nèi)部:結(jié)果依舊相同!
class NestTry {static void nesttry(int a) {try {if (a == 1) {a = a / (a - a);}if (a == 2) {int c[] = {1};c[42] = 99;}} catch (ArrayIndexOutOfBoundsException e) {System.out.println( "ArrayIndexOutOfBounds :" + e );}}public static void main(String[] args) {try {int a = args.length;int b = 42 / a;System.out.println( "a = " + a );nesttry( a );} catch (ArithmeticException e) {System.out.println( "Divide by 0" + e );}}
}
2、thorw
到目前為止,我們只是獲取了被Java運(yùn)行時(shí)系統(tǒng)引發(fā)的異常。然而,我們還可以用throw語(yǔ)句拋出明確的異常。
語(yǔ)法形式:
throw ThrowableInstance;
這里的ThrowableInstance一定是 Throwable 類(lèi)類(lèi)型或者 Throwable 子類(lèi)類(lèi)型的一個(gè)對(duì)象。簡(jiǎn)單的數(shù)據(jù)類(lèi)型,例如int, char ,以及非 Throwable 類(lèi),例如 String 或Object,不能用作異常。
有兩種方法可以獲取 Throwable 對(duì)象:在 catch 子句中使用參數(shù)或者使用 new 操作符創(chuàng)建。程
序執(zhí)行完throw語(yǔ)句之后立即停止; throw后面的任何語(yǔ)句不被執(zhí)行,最鄰近的 try塊用來(lái)檢
查它是否含有一個(gè)與異常類(lèi)型匹配的 catch 語(yǔ)句。
如果發(fā)現(xiàn)了匹配的塊,控制轉(zhuǎn)向該語(yǔ)句;如果沒(méi)有發(fā)現(xiàn),次包圍的 try塊來(lái)檢查,以此類(lèi)推。如果沒(méi)
有發(fā)現(xiàn)匹配的catch 塊,默認(rèn)異常處理程序中斷程序的執(zhí)行并且打印堆棧軌跡。
class TestThrow{static void proc(){try{throw new NullPointerException("demo");}catch(NullPointerException e){System.out.println("Caught inside proc");throw e;}}public static void main(String [] args){try{proc();}catch(NullPointerException e){System.out.println("Recaught: "+e);}}
}
該程序兩次處理相同的錯(cuò)誤,首先, main() 方法設(shè)立了一個(gè)異常關(guān)系然后調(diào)用proc()。proc()方法設(shè)立了另一個(gè)異常處理關(guān)系并且立即拋出一個(gè)NullPointerException 實(shí)例,
NullPointerException 在 main() 中被再次捕獲。該程序闡述了怎樣創(chuàng)建Java的標(biāo)準(zhǔn)異常對(duì)象,特別注意這一行:
throw new NullPointerException("demo");
分析:此處 new 用來(lái)構(gòu)造一個(gè)NullPointerException 實(shí)例,所有的Java內(nèi)置的運(yùn)行時(shí)異常有兩個(gè)構(gòu)造方法:一個(gè)沒(méi)有參數(shù),一個(gè)帶有一個(gè)字符串參數(shù)。
當(dāng)用第二種形式時(shí),參數(shù)指定描述異常的字符串。如果對(duì)象用作 print() 或者 println() 的參數(shù)時(shí),該字符串被顯示。這同樣可以通過(guò)調(diào)用getMessage()來(lái)實(shí)現(xiàn),getMessage()是由 Throwable 定義的。
3、throws
如果一個(gè)方法可以導(dǎo)致一個(gè)異常但不處理它,它必須指定這種行為以使方法的調(diào)用者可以保護(hù)它們自己而不發(fā)生異常。要做到這點(diǎn),我們可以在方法聲明中包含一個(gè)throws 子句。
一個(gè) throws 子句列舉了一個(gè)方法可能引發(fā)的所有異常類(lèi)型。這對(duì)于除了Error 或
RuntimeException 及它們子類(lèi)以外類(lèi)型的所有異常是必要的。一個(gè)方法可以引發(fā)的所有其他類(lèi)型的異常必須在 throws 子句中聲明,否則會(huì)導(dǎo)致編譯錯(cuò)誤。
public void info() throws Exception
{//body of method
}
Exception 是該方法可能引發(fā)的所有的異常,也可以是異常列表,中間以逗號(hào)隔開(kāi)。
【例子】
class TestThrows {static void throw1() {System.out.println( "Inside throw1 . " );throw new IllegalAccessException( "demo" );}public static void main(String[] args) {throw1();}
}
上述例子中有兩個(gè)地方存在錯(cuò)誤,你能看出來(lái)嗎?
該例子中存在兩個(gè)錯(cuò)誤,首先,throw1()方法不想處理所導(dǎo)致的異常,因而它必須聲明throws 子句來(lái)列舉可能引發(fā)的異常即IllegalAccessException;其次,main()方法必須定義try/catch 語(yǔ)句來(lái)捕獲該異常。
正確例子如下:
class TestThrows{static void throw1() throws IllegalAccessException {System.out.println("Inside throw1 . ");throw new IllegalAccessException("demo"); 5}public static void main(String[] args){try {throw1();}catch(IllegalAccessException e ){System.out.println("Caught " + e); 11}}
}
throws拋出異常的規(guī)則:
-
如果是不受檢查異常( unchecked exception ),即 Error 、 RubntimeException 或它們的子類(lèi),那么可以不使用 throws 關(guān)鍵字來(lái)聲明要拋出的異常,編譯仍能順利通過(guò),但在運(yùn)行時(shí)會(huì)被系統(tǒng)拋出。
-
必須聲明方法可拋出的任何檢查異常(checked exception )。即如果一個(gè)方法可能出現(xiàn)受可查異常,要么用try/catch 語(yǔ)句捕獲,要么用 throws子句聲明將它拋出,否則會(huì)導(dǎo)致編譯錯(cuò)誤
-
拋出了異常,該方法的調(diào)用者才必須處理或者重新拋出該異常。當(dāng)方法的調(diào)用者無(wú)力處理該異常的時(shí)候,應(yīng)該繼續(xù)拋出,而不是囫圇吞棗。
-
調(diào)用方法必須遵循任何可查異常的處理和聲明規(guī)則。若覆蓋一個(gè)方法,則不能聲明與覆蓋方法不同 的異常。聲明的任何異常必須是被覆蓋方法所聲明異常的同類(lèi)或子類(lèi)。
4、?nally
當(dāng)異常發(fā)生時(shí),通常方法的執(zhí)行將做一個(gè)陡峭的非線(xiàn)性的轉(zhuǎn)向,它甚至?xí)^(guò)早的導(dǎo)致方法返回。例如, 如果一個(gè)方法打開(kāi)了一個(gè)文件并關(guān)閉,然后退出,你不希望關(guān)閉文件的代碼被異常處理機(jī)制旁路。
?nally關(guān)鍵字為處理這種意外而設(shè)計(jì)。
?nally創(chuàng)建的代碼塊在try/catch 塊完成之后另一個(gè) try/catch 出現(xiàn)之前執(zhí)行。
?nally 塊無(wú)論有沒(méi)有異常拋出都會(huì)執(zhí)行。如果拋出異常,即使沒(méi)有 catch 子句匹配,
?nally 也會(huì)執(zhí)行。
一個(gè)方法將從一個(gè) try/catch 塊返回到調(diào)用程序的任何時(shí)候,經(jīng)過(guò)一個(gè)未捕獲的異?;蛘呤且粋€(gè)明確的返回語(yǔ)句, ?nally 子句在方法返回之前仍將執(zhí)行。這在關(guān)閉文件句柄和釋放任何在方法開(kāi)始時(shí)被分配的其他資源是很有用。
注意: ?nally子句是可選項(xiàng),可以有也可以無(wú),但是每個(gè) try 語(yǔ)句至少需要一個(gè) catch 或者?nally 子句。
【例子】
class TestFinally{static void proc1(){try{System.out.println("inside proc1");throw new RuntimeException("demo");}finally{System.out.println("proc1's finally");}}static void proc2(){try{System.out.println("inside proc2");return ;} finally{System.out.println("proc2's finally");}}static void proc3(){try{System.out.println("inside proc3");}finally{System.out.println("proc3's finally");}}public static void main(String [] args){try{proc1();}catch(Exception e){System.out.println("Exception caught");}proc2();proc3();}
}結(jié)果:
inside proc1proc1's finallyException caughtinside proc2proc2's finallyinside proc3proc3's finally
注:如果?nally塊與一個(gè)try 聯(lián)合使用,?nally塊將在try 結(jié)束之前執(zhí)行。
try, catch,?nally ,return 執(zhí)行順序
-
執(zhí)行try,catch , 給返回值賦值
-
執(zhí)行?nally
-
3.return
自定義異常
使用Java內(nèi)置的異常類(lèi)可以描述在編程時(shí)出現(xiàn)的大部分異常情況。除此之外,用戶(hù)還可以自定義異常。
用戶(hù)自定義異常類(lèi),只需繼承Exception 類(lèi)即可。
在程序中使用自定義異常類(lèi),大體可分為以下幾個(gè)步驟:
-
創(chuàng)建自定義異常類(lèi)。
-
在方法中通過(guò)throw關(guān)鍵字拋出異常對(duì)象。
-
如果在當(dāng)前拋出異常的方法中處理異常,可以使用try/catch 語(yǔ)句捕獲并處理;否則在方法的聲明處通過(guò)throws關(guān)鍵字指明要拋出給方法調(diào)用者的異常,繼續(xù)進(jìn)行下一步操作。
-
在出現(xiàn)異常方法的調(diào)用者中捕獲并處理異常。
【舉例】
class MyException extends Exception {private int detail;MyException(int a) {detail = a;}public String toString() {return "MyException [" + detail + "]";}
}public class TestMyException {static void compute(int a) throws MyException {System.out.println( "Called compute(" + a + ")" );if (a > 10) {throw new MyException( a );}System.out.println( "Normal exit!" );}public static void main(String[] args) {try {compute( 1 );compute( 20 );} catch (MyException me) {System.out.println( "Caught " + me );}}
}
【結(jié)果】
Called compute(1)
Normal exit!
Called compute(20)
Caught MyException [20]
總結(jié)
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-BAOgMH59-1657115739292)(C:\Users\chene\AppData\Roaming\Typora\typora-user-images\image-20220706225211505.png)]
開(kāi)發(fā)中
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-c8dUwZ4x-1657115739296)(C:\Users\chene\AppData\Roaming\Typora\typora-user-images\image-20220706225221229.png)]