第三章 異常
3.1 異常概念
異常,就是不正常的意思。在生活中:醫(yī)生說(shuō),你的身體某個(gè)部位有異常,該部位和正常相比有點(diǎn)不同,該部位的功能將受影響.在程序中的意思就是:
-
異常 :指的是程序在執(zhí)行過(guò)程中,出現(xiàn)的非正常的情況,最終會(huì)導(dǎo)致JVM的非正常停止。
在Java等面向?qū)ο蟮木幊陶Z(yǔ)言中,異常本身是一個(gè)類,產(chǎn)生異常就是創(chuàng)建異常對(duì)象并拋出了一個(gè)異常對(duì)象。Java處理異常的方式是中斷處理。
異常指的并不是語(yǔ)法錯(cuò)誤,語(yǔ)法錯(cuò)了,編譯不通過(guò),不會(huì)產(chǎn)生字節(jié)碼文件,根本不能運(yùn)行.
3.2 異常體系
異常機(jī)制其實(shí)是幫助我們找到程序中的問(wèn)題,異常的根類是java.lang.Throwable
,其下有兩個(gè)子類:java.lang.Error
與java.lang.Exception
,平常所說(shuō)的異常指java.lang.Exception
。
還有:
小結(jié):
Throwable體系:
Error:嚴(yán)重錯(cuò)誤Error,無(wú)法通過(guò)處理的錯(cuò)誤,只能事先避免,好比絕癥。它是系統(tǒng)級(jí)別的問(wèn)題。
Exception:表示異常,異常產(chǎn)生后程序員可以通過(guò)代碼的方式糾正,使程序繼續(xù)運(yùn)行,是必須要處理的。好比感冒、闌尾炎。
Throwable中的常用方法:
public void printStackTrace()
:打印異常的詳細(xì)信息。包含了異常的類型,異常的原因,還包括異常出現(xiàn)的位置,在開(kāi)發(fā)和調(diào)試階段,都得使用printStackTrace。
public String getMessage()
:獲取發(fā)生異常的原因。提示給用戶的時(shí)候,就提示錯(cuò)誤原因。
public String toString()
:獲取異常的類型和異常描述信息(不用)。
出現(xiàn)異常,不要緊張,把異常的簡(jiǎn)單類名,拷貝到API中去查。
3.3 異常分類
我們平常說(shuō)的異常就是指Exception,因?yàn)檫@類異常一旦出現(xiàn),我們就要對(duì)代碼進(jìn)行更正,修復(fù)程序。
異常(Exception)的分類:根據(jù)在編譯時(shí)期還是運(yùn)行時(shí)期去檢查異常?
編譯時(shí)期異常:checked異常。在編譯時(shí)期,就會(huì)檢查,如果沒(méi)有處理異常,則編譯失敗。(如日期格式化異常)
運(yùn)行時(shí)期異常:runtime異常。在運(yùn)行時(shí)期,檢查異常.在編譯時(shí)期,運(yùn)行異常不會(huì)編譯器檢測(cè)(不報(bào)錯(cuò))。(如數(shù)學(xué)異常,除數(shù)為0)
兩種異常對(duì)比:
運(yùn)行異常:
編譯異常:
3.4 異常的產(chǎn)生過(guò)程解析
先運(yùn)行下面的程序,程序會(huì)產(chǎn)生一個(gè)數(shù)組索引越界異常ArrayIndexOfBoundsException。我們通過(guò)圖解來(lái)解析下異常產(chǎn)生的過(guò)程。
工具類
public class ArrayTools { ? ?// 對(duì)給定的數(shù)組通過(guò)給定的角標(biāo)獲取元素。 ? ?public static int getElement(int[] arr, int index) { ? ? ? ?int element = arr[index]; ? ? ? ?return element; ? } }
測(cè)試類
public class ExceptionDemo { ? ?public static void main(String[] args) { ? ? ? ?int[] arr = { 34, 12, 67 }; ? ? ? ?intnum = ArrayTools.getElement(arr, 4) ? ? ? ?System.out.println("num=" + num); ? ? ? ?System.out.println("over"); ? } }
上述程序執(zhí)行過(guò)程圖解:
第四章 異常的處理
默認(rèn)異常處理:先看例子:
小結(jié):
?
其它三種處理方式:
Java異常處理的五個(gè)關(guān)鍵字:try、catch、finally、throw、throws
4.1 拋出異常throw
在編寫(xiě)程序時(shí),我們必須要考慮程序出現(xiàn)問(wèn)題的情況。比如,在定義方法時(shí),方法需要接受參數(shù)。那么,當(dāng)調(diào)用方法使用接受到的參數(shù)時(shí),首先需要先對(duì)參數(shù)數(shù)據(jù)進(jìn)行合法的判斷,數(shù)據(jù)若不合法,就應(yīng)該告訴調(diào)用者,傳遞合法的數(shù)據(jù)進(jìn)來(lái)。這時(shí)需要使用拋出異常的方式來(lái)告訴調(diào)用者。
在java中,提供了一個(gè)throw關(guān)鍵字,它用來(lái)拋出一個(gè)指定的異常對(duì)象。那么,拋出一個(gè)異常具體如何操作呢?
創(chuàng)建一個(gè)異常對(duì)象。封裝一些提示信息(信息可以自己編寫(xiě))。
需要將這個(gè)異常對(duì)象告知給調(diào)用者。怎么告知呢?怎么將這個(gè)異常對(duì)象傳遞到調(diào)用者處呢?通過(guò)關(guān)鍵字throw就可以完成。throw 異常對(duì)象**。
throw用在方法內(nèi),用來(lái)拋出一個(gè)異常對(duì)象,將這個(gè)異常對(duì)象傳遞到調(diào)用者處,并結(jié)束當(dāng)前方法的執(zhí)行。
使用格式:
throw new 異常類名(參數(shù));
例如:
throw new NullPointerException("要訪問(wèn)的arr數(shù)組不存在"); ? throw new ArrayIndexOutOfBoundsException("該索引在數(shù)組中不存在,已超出范圍");
學(xué)習(xí)完拋出異常的格式后,我們通過(guò)下面程序演示下throw的使用。
public class ThrowDemo { ? ?public static void main(String[] args) { ? ? ? ?//創(chuàng)建一個(gè)數(shù)組 ? ? ? ?int[] arr = {2,4,52,2}; ? ? ? ?//根據(jù)索引找對(duì)應(yīng)的元素 ? ? ? ?int index = 4; ? ? ? ?int element = getElement(arr, index); ? ? ? ? ?System.out.println(element); ? ? ? ?System.out.println("over"); ? } ? ?/* ? ? * 根據(jù) 索引找到數(shù)組中對(duì)應(yīng)的元素 ? ? */ ? ?public static int getElement(int[] arr,int index){ ? ? ? //判斷 索引是否越界 ? ? ? ?if(index<0 || index>arr.length-1){ ? ? ? ? ? ? /* ? ? ? ? ? ? 判斷條件如果滿足,當(dāng)執(zhí)行完throw拋出異常對(duì)象后,方法已經(jīng)無(wú)法繼續(xù)運(yùn)算。 ? ? ? ? ? ? 這時(shí)就會(huì)結(jié)束當(dāng)前方法的執(zhí)行,并將異常告知給調(diào)用者。這時(shí)就需要通過(guò)異常來(lái)解決。 ? ? ? ? ? ? ?*/ ? ? ? ? ? ? throw new ArrayIndexOutOfBoundsException("哥們,角標(biāo)越界了```"); ? ? ? } ? ? ? ?int element = arr[index]; ? ? ? ?return element; ? } } ?
運(yùn)行結(jié)果:
?
注意:如果產(chǎn)生了問(wèn)題,我們就會(huì)throw將問(wèn)題描述類即異常進(jìn)行拋出,也就是將問(wèn)題返回給該方法的調(diào)用者。main()方法的調(diào)用者是JVM(虛擬機(jī))
那么對(duì)于調(diào)用者來(lái)說(shuō),該怎么處理呢?一種是進(jìn)行捕獲處理,另一種就是繼續(xù)講問(wèn)題聲明出去,使用throws聲明處理。
4.2 聲明異常throws
聲明異常:將問(wèn)題標(biāo)識(shí)出來(lái),報(bào)告給調(diào)用者。如果方法內(nèi)通過(guò)throw拋出了編譯時(shí)異常,而沒(méi)有捕獲處理(稍后講解該方式),那么必須通過(guò)throws進(jìn)行聲明,讓調(diào)用者去處理。
關(guān)鍵字throws運(yùn)用于方法聲明之上,用于表示當(dāng)前方法不處理異常,而是提醒該方法的調(diào)用者來(lái)處理異常(拋出異常).
聲明異常格式:
修飾符 返回值類型 方法名(參數(shù)) throws 異常類名1,異常類名2…{ ? }
聲明異常的代碼演示:
public class ThrowsDemo { ? ?public static void main(String[] args) throws FileNotFoundException { ? ? ? ?read("a.txt"); ? } ? ? ?// 如果定義功能時(shí)有問(wèn)題發(fā)生需要報(bào)告給調(diào)用者。可以通過(guò)在方法上使用throws關(guān)鍵字進(jìn)行聲明 ? ?public static void read(String path) throws FileNotFoundException { ? ? ? ?if (!path.equals("a.txt")) {//如果不是 a.txt這個(gè)文件 ? ? ? ? ? ?// 我假設(shè) 如果不是 a.txt 認(rèn)為 該文件不存在 是一個(gè)錯(cuò)誤 也就是異常 throw ? ? ? ? ? ?throw new FileNotFoundException("文件不存在"); ? ? ? } ? } }
throws用于進(jìn)行異常類的聲明,若該方法可能有多種異常情況產(chǎn)生,那么在throws后面可以寫(xiě)多個(gè)異常類,用逗號(hào)隔開(kāi)。
public class ThrowsDemo2 { ? ?public static void main(String[] args) throws IOException { ? ? ? ?read("a.txt"); ? } ? ? ?public static void read(String path)throws FileNotFoundException, IOException { ? ? ? ?if (!path.equals("a.txt")) {//如果不是 a.txt這個(gè)文件 ? ? ? ? ? ?// 我假設(shè) 如果不是 a.txt 認(rèn)為 該文件不存在 是一個(gè)錯(cuò)誤 也就是異常 throw ? ? ? ? ? ?throw new FileNotFoundException("文件不存在"); ? ? ? } ? ? ? ?if (!path.equals("b.txt")) { ? ? ? ? ? ?throw new IOException(); ? ? ? } ? } }
4.3 捕獲異常try…catch
如果異常出現(xiàn)的話,會(huì)立刻終止程序,所以我們得處理異常:
該方法不處理,而是聲明拋出,由該方法的調(diào)用者來(lái)處理(throws)。
在方法中使用try-catch的語(yǔ)句塊來(lái)處理異常。
try-catch的方式就是捕獲異常。
-
捕獲異常:Java中對(duì)異常有針對(duì)性的語(yǔ)句進(jìn)行捕獲,可以對(duì)出現(xiàn)的異常進(jìn)行指定方式的處理。
捕獲異常語(yǔ)法如下:(捕獲語(yǔ)句格式類比C語(yǔ)言的switch關(guān)鍵字)
try{ ? ? 編寫(xiě)可能會(huì)出現(xiàn)異常的代碼 }catch(異常類型 ?e){ ? ? 處理異常的代碼 ? ? //記錄日志/打印異常信息/繼續(xù)拋出異常 }
try:該代碼塊中編寫(xiě)可能產(chǎn)生異常的代碼。
catch:用來(lái)進(jìn)行某種異常的捕獲,實(shí)現(xiàn)對(duì)捕獲到的異常進(jìn)行處理。
注意:try和catch都不能單獨(dú)使用,必須連用。
演示如下:
public class TryCatchDemo { ? ?public static void main(String[] args) { ? ? ? ?try {// 當(dāng)產(chǎn)生異常時(shí),必須有處理方式。要么捕獲,要么聲明。 ? ? ? ? ? ?read("b.txt"); ? ? ? } catch (FileNotFoundException e) {// 括號(hào)中需要定義什么呢? ? ? ? ? //try中拋出的是什么異常,在括號(hào)中就定義什么異常類型 ? ? ? ? ? ?System.out.println(e); ? ? ? } ? ? ? ?System.out.println("over"); ? } ? ?/* ? ? * ? ? * 我們 當(dāng)前的這個(gè)方法中 有異常 有編譯期異常 ? ? */ ? ?public static void read(String path) throws FileNotFoundException { ? ? ? ?if (!path.equals("a.txt")) {//如果不是 a.txt這個(gè)文件 ? ? ? ? ? ?// 我假設(shè) 如果不是 a.txt 認(rèn)為 該文件不存在 是一個(gè)錯(cuò)誤 也就是異常 throw ? ? ? ? ? ?throw new FileNotFoundException("文件不存在"); ? ? ? } ? } }
如何獲取異常信息:
Throwable類中定義了一些查看方法:
public String getMessage()`:獲取異常的描述信息,原因(提示給用戶的時(shí)候,就提示錯(cuò)誤原因。
public String toString()
:獲取異常的類型和異常描述信息(不用)。
public void printStackTrace()
:打印異常的跟蹤棧信息并輸出到控制臺(tái)。
包含了異常的類型,異常的原因,還包括異常出現(xiàn)的位置,在開(kāi)發(fā)和調(diào)試階段,都得使用printStackTrace。
在開(kāi)發(fā)中呢也可以在catch將編譯期異常轉(zhuǎn)換成運(yùn)行期異常處理。
多個(gè)異常使用捕獲又該如何處理呢?
多個(gè)異常分別處理。
多個(gè)異常一次捕獲,多次處理。
多個(gè)異常一次捕獲一次處理。
一般我們是使用一次捕獲多次處理方式,格式如下:
try{ ? ? 編寫(xiě)可能會(huì)出現(xiàn)異常的代碼 }catch(異常類型A ?e){ ?當(dāng)try中出現(xiàn)A類型異常,就用該catch來(lái)捕獲. ? ? 處理異常的代碼 ? ? //記錄日志/打印異常信息/繼續(xù)拋出異常 }catch(異常類型B ?e){ ?當(dāng)try中出現(xiàn)B類型異常,就用該catch來(lái)捕獲. ? ? 處理異常的代碼 ? ? //記錄日志/打印異常信息/繼續(xù)拋出異常 }
注意:這種異常處理方式,要求多個(gè)catch中的異常不能相同,并且若catch中的多個(gè)異常之間有子父類異常的關(guān)系,那么子類異常要求在上面的catch處理,父類異常在下面的catch處理(這是個(gè)重點(diǎn),就是父類異常只能寫(xiě)在子類異常下面)。
4.4 異常注意事項(xiàng)
運(yùn)行時(shí)異常被拋出可以不處理。即不捕獲也不聲明拋出。
當(dāng)多異常處理時(shí),捕獲處理,前邊的類不能是后邊類的父類(重點(diǎn)?。?/strong>
第五章 自定義異常
5.1 概述
為什么需要自定義異常類:
我們說(shuō)了Java中不同的異常類,分別表示著某一種具體的異常情況,那么在開(kāi)發(fā)中總是有些異常情況是JDK沒(méi)有定義好的,此時(shí)我們根據(jù)自己業(yè)務(wù)的異常情況來(lái)定義異常類。,例如年齡負(fù)數(shù)問(wèn)題,考試成績(jī)負(fù)數(shù)問(wèn)題。
在上述代碼中,發(fā)現(xiàn)這些異常都是JDK內(nèi)部定義好的,但是實(shí)際開(kāi)發(fā)中也會(huì)出現(xiàn)很多異常,這些異常很可能在JDK中沒(méi)有定義過(guò),例如年齡負(fù)數(shù)問(wèn)題,考試成績(jī)負(fù)數(shù)問(wèn)題.那么能不能自己定義異常呢?
什么是自定義異常類:
在開(kāi)發(fā)中根據(jù)自己業(yè)務(wù)的異常情況來(lái)定義異常類.
自定義一個(gè)業(yè)務(wù)邏輯異常: LoginException。一個(gè)登陸異常類。
異常類如何定義:
自定義一個(gè)編譯期異常: 自定義類 并繼承于
java.lang.Exception
。自定義一個(gè)運(yùn)行時(shí)期的異常類:自定義類 并繼承于
java.lang.RuntimeException
。
5.2 自定義異常的練習(xí)
首先我們要知道自定義異常的核心不在于它的邏輯,而是在于它的命名!要做到見(jiàn)明知意!而且是那種非常清楚的見(jiàn)明知意。
要求:鍵盤(pán)錄入學(xué)生信息,年齡在18~40之間文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-423899.html
首先定義一個(gè)登陸異常類AgeOutofBoundException:文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-423899.html
public class AgeOutofBoundException extends RuntimeException{ ? ?//生成構(gòu)造方法 ? ?//空參 帶參 ? ? ? ?public AgeOutofBoundException() { ? } ? ? ?public AgeOutofBoundException(String message) { ? ? ? ?super(message); ? } } ?
public class Test1 { ? ?public static void main(String[] args) { ? ? ? ?Student s = new Student(); ? ? ? ?//1.鍵盤(pán)錄入姓名 ? ? ? ?Scanner sc = new Scanner(System.in); ? ? ? ?System.out.println("請(qǐng)輸入姓名"); ? ? ? ?String name = sc.nextLine(); ? ? ? ?s.setName(name); ? ? ? ?while (true) { ? ? ? ? ? ?System.out.println("請(qǐng)輸入年齡"); ? ? ? ? ? ?String ageStr = sc.nextLine(); ? ? ? ? ? ?try { ? ? ? ? ? ? ? ?int age = Integer.parseInt(ageStr); ? ? ? ? ? ? ? ?//表示age一定是純數(shù)字,但是有可能超出范圍 ? ? ? ? ? ? ? ?s.setAge(age); ? ? ? ? ? ? ? ?//如果set的時(shí)候數(shù)據(jù)是正確的,那么賦值成功,跳出循環(huán) ? ? ? ? ? ? ? ?break; ? ? ? ? ? } catch (NumberFormatException e) { ? ? ? ? ? ? ? ?System.out.println("年齡的格式有誤,請(qǐng)輸入純數(shù)字"); ? ? ? ? ? ? ? ?continue; ? ? ? ? ? } catch (AgeOutofBoundException e) { ? ? ? ? ? ? ? ?e.printStackTrace(); ? ? ? ? ? ? ? ?System.out.println("年齡超出了范圍"); ? ? ? ? ? ? ? ?continue; ? ? ? ? ? } ? ? ? } ? ? ? ? ?System.out.println(s); ? } }
public class Student { ? ?private String name; ? ?private int age; ? ? ? ? ?public Student() { ? } ? ? ?public Student(String name, int age) { ? ? ? ?this.name = name; ? ? ? ?this.age = age; ? } ? ? ?/** ? ? * 獲取 ? ? * ? ? * @return name ? ? */ ? ?public String getName() { ? ? ? ?return name; ? } ? ? ?/** ? ? * 設(shè)置 ? ? * ? ? * @param name ? ? */ ? ?public void setName(String name) { ? ? ? ?this.name = name; ? } ? ? ?/** ? ? * 獲取 ? ? * ? ? * @return age ? ? */ ? ?public int getAge() { ? ? ? ?return age; ? } ? ? ?/** ? ? * 設(shè)置 ? ? * ? ? * @param age ? ? */ ? ?public void setAge(int age) { ? ? ? ?if(age >= 18 && age <= 40){ ? ? ? ? ? ?this.age = age; ? ? ? }else{ ? ? ? ? ? ?//我們就可以手動(dòng)造一個(gè)異常對(duì)象,交給調(diào)用者 ? ? ? ? ? ?//告訴他這里出現(xiàn)了問(wèn)題 ? ? ? ? ? ?throw new AgeOutofBoundException(age + "超出范圍"); ? ? ? } ? ? } ? ? ?public String toString() { ? ? ? ?return "Student{name = " + name + ", age = " + age + "}"; ? } } ?
到了這里,關(guān)于JavaSE學(xué)習(xí)進(jìn)階day07_02 異常的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!