??“人生就像一盤棋,有時(shí)候你慢一步,就輸?shù)袅艘痪?。但只要你不停止思考和行?dòng),就永遠(yuǎn)有機(jī)會(huì)翻盤?!??
??作者:不能再留遺憾了??
??專欄:Java學(xué)習(xí)??
??本文章主要內(nèi)容:詳細(xì)講解Java異常??
什么是異常
Java是一種面向?qū)ο缶幊陶Z(yǔ)言,提供了一種強(qiáng)大的異常處理機(jī)制。Java異常是一個(gè)事件,它發(fā)生在程序執(zhí)行過程中導(dǎo)致程序中斷或出錯(cuò)。當(dāng)發(fā)生異常時(shí),Java程序會(huì)自動(dòng)創(chuàng)建一個(gè)異常對(duì)象來表示該異常,并將異常對(duì)象傳遞給相應(yīng)的異常處理程序來處理。
Java異常機(jī)制的主要目的是使程序更加可靠,因?yàn)樵诎l(fā)生異常時(shí),程序并不會(huì)異常終止,而是將異常傳遞給異常處理程序來處理。Java異常處理機(jī)制提供了一種強(qiáng)大的工具,使得程序能夠處理錯(cuò)誤情況,以便程序可以回復(fù)并繼續(xù)執(zhí)行。在Java中,異??梢苑譃閮煞N類型:受查異常和非受查異常。
受查異常
受查異常也叫編譯異常,是指在編譯時(shí)必須顯式地聲明拋出該異常,否則編譯器將會(huì)報(bào)錯(cuò)。受查異常通常是程序可以預(yù)料到并可能解決的異常,例如文件不存在、網(wǎng)絡(luò)連接異常等。如果程序在編譯時(shí)沒有正確地處理受查異常,將會(huì)導(dǎo)致編譯錯(cuò)誤。
下面是一個(gè)示例代碼,它使用了Java的IOException異常,這是一種受查異常。
import java.io.*;
public class FileHandling {
public static void main(String args[]) {
try {
File file = new File("file.txt");
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
String line;
while((line = br.readLine()) != null) {
System.out.println(line);
}
br.close();
} catch(IOException e) {
e.printStackTrace();
}
}
}
在上面的代碼中,我們通過FileReader讀取文件內(nèi)容,并使用BufferedReader逐行讀取文件內(nèi)容。由于讀取文件時(shí)可能會(huì)發(fā)生異常,我們需要在try-catch塊中捕獲并處理IOException異常。
非受查異常
非受查異常是指在編譯時(shí)無須聲明拋出該異常。通常情況下,非受查異常是由于程序中出現(xiàn)了錯(cuò)誤,例如除數(shù)為零、數(shù)組下標(biāo)越界等,并且發(fā)生這些異常時(shí),程序無法自行恢復(fù)。因此,非受查異常通常會(huì)導(dǎo)致程序異常終止。
在Java中,非受查異常包括RuntimeException及其子類,例如NullPointerException(空指針異常)、ArrayIndexOutOfBoundsException(數(shù)組越界異常)、ArithmeticException(除數(shù)為0異常)等。這些異常通常是程序出現(xiàn)邏輯錯(cuò)誤時(shí)才會(huì)產(chǎn)生。
下面是一個(gè)示例代碼,它使用了Java的ArithmeticException異常,這是一種非受查異常。
public class Example {
public static void main(String args[]) {
int a = 10, b = 0;
try {
int c = a / b;
System.out.println("Result: " + c);
} catch(ArithmeticException e) {
System.out.println("Exception caught: " + e);
}
}
}
在上面的代碼中,我們嘗試將10除以0,這會(huì)導(dǎo)致ArithmeticException異常的發(fā)生。由于程序無法自行恢復(fù)該異常,我們需要在try-catch塊中捕獲并處理該異常。
當(dāng)出現(xiàn)異常的時(shí)候,我們必須自己手動(dòng)處理這些異常,否則這些異常就會(huì)交給JVM處理,如果交給JVM處理,那么程序就會(huì)異常終止。
舉個(gè)不恰當(dāng)?shù)睦?,?dāng)你犯事的時(shí)候,如果只是你的父母發(fā)現(xiàn)知道了,那么你的父母可能會(huì)幫助你解決問題并且不告訴警察;但是如果你的父母不知道,但是被警察知道了,那么你就會(huì)被法律制裁。
怎樣處理異常
事前防御型異常
Java中的事前防御型異常(Proactive Defense)指的是在代碼開發(fā)階段預(yù)先考慮和處理異常情況,以提高應(yīng)用程序的健壯性和穩(wěn)定性。事前防御型異常意味著通過將異常情況納入代碼設(shè)計(jì)和實(shí)現(xiàn)過程,盡可能主動(dòng)地防止異常情況的發(fā)生,而不僅是在異常發(fā)生后采取響應(yīng)措施。
意思也就是說:我根本不給你犯罪的機(jī)會(huì),從你有這個(gè)萌芽的時(shí)候就扼殺你。
public static int length(String s) {
if(s == null) {
return -1;
}
return s.length();
}
public static void main(String[] args) {
System.out.println(length("abdias"));
}
當(dāng)我們用length來求字符串的長(zhǎng)度時(shí)(有點(diǎn)多此一舉了啊),你想要訪問null的時(shí)候,我直接終止這個(gè)length,不讓你訪問null。這就是事前防御型異常。
事后認(rèn)錯(cuò)型異常
Java中的事后認(rèn)錯(cuò)型異常(Post-mortem Defense)是指在應(yīng)用程序運(yùn)行時(shí)發(fā)生異常時(shí)采取的響應(yīng)措施。如果應(yīng)用程序無法避免發(fā)生異常情況,那么事后認(rèn)錯(cuò)型異常就是在程序發(fā)生異常后對(duì)異常進(jìn)行收集和處理,以恢復(fù)應(yīng)用程序的穩(wěn)定性和可靠性。
Java中可以使用try-catch-finally塊來捕獲和處理發(fā)生的異常。try塊中包含可能會(huì)引發(fā)異常的代碼,catch塊用于捕獲處理異常情況,finally塊用于確保代碼塊中的資源得到釋放(即使異常發(fā)生)。
try {
可能會(huì)出現(xiàn)異常的代碼塊
}catch(捕獲的異常) {
處理異常
}finally {
確保代碼塊中的資源得到釋放
}
我們今天主要講的就是事后認(rèn)錯(cuò)型異常。
異常的拋出
我們使用throw關(guān)鍵字來拋出一個(gè)指定的異常對(duì)象。
public static int length(String s) {
if(s == null) {
throw new NullPointerException("字符串引用指向null");
}
return s.length();
}
public static void main(String[] args) {
System.out.println(length(null));
}
這里會(huì)將你出錯(cuò)的位置給你指出來,方便改正。
我們?cè)賮硭伎家粋€(gè)問題,就是如果這里拋出異常了,那么當(dāng)出現(xiàn)異常的時(shí)候,其后面的代碼還會(huì)執(zhí)行嗎?
public static int length(String s,int a) {
if(s == null) {
throw new NullPointerException("字符串引用指向null");
a = 20;
}
return s.length();
}
public static void main(String[] args) {
int a = 10;
System.out.println(length(null,a));
System.out.println(a);
}
這里標(biāo)紅了,我們將鼠標(biāo)放上去,可以看到提示,提示這個(gè)語(yǔ)句是不可能達(dá)到的,也就是說,當(dāng)你s指向的不為null時(shí),if語(yǔ)句根本就進(jìn)不去,如果s指向的是null時(shí),程序也不會(huì)走到a = 20這個(gè)語(yǔ)句,所以拋出異常的語(yǔ)句如果出現(xiàn)了異常,那么后面的語(yǔ)句將不會(huì)執(zhí)行。
注意事項(xiàng)
1. throw必須寫在方法體內(nèi)部
2. 拋出的對(duì)象必須是Exception 或者 Exception 的子類對(duì)象
3. 如果拋出的是 RunTimeException 或者 RunTimeException 的子類,則可以不用處理,直接交給JVM來處理
4. 如果拋出的是編譯時(shí)異常,用戶必須處理,否則無法通過編譯
5. 異常一旦拋出,其后的代碼就不會(huì)執(zhí)行
異常的捕獲
throws捕獲異常
當(dāng)你在方法參數(shù)的后面使用throws異常類型時(shí),表明你這個(gè)方法可能會(huì)出現(xiàn)此類異常,但是在此方法中不處理異常,只是告訴你調(diào)用者會(huì)出現(xiàn)異常,具體怎樣處理,需要你調(diào)用者處理。
public static int length(String s) throws NullPointerException{
if(s == null) {
throw new NullPointerException("字符串引用指向null");
}
return s.length();
}
public static void main(String[] args) {
int a = 10;
System.out.println(length(null));
System.out.println(a);
}
就先這樣,我length方法只是告訴你出現(xiàn)了空指針異常,但是空指針異常解決了嗎?并沒有,所以我們?cè)诜椒▍?shù)后面使用throws 異常類型只是告訴調(diào)用者會(huì)出現(xiàn)那種類型的異常,具體解決需要調(diào)用者解決。如果你調(diào)用者沒有解決異常,那么就需要繼續(xù)用throws拋出異常。
注意事項(xiàng)
1. throws必須跟在方法的參數(shù)列表之后
2. 聲明的異常必須是 Exception 或者 Exception 的子類
3. 方法內(nèi)部如果拋出了多個(gè)異常,throws之后必須跟多個(gè)異常類型,之間用逗號(hào)隔開,如果拋出多個(gè)異常類型具有父子關(guān)系,直接聲明父類即可。
如果我們想要解決這個(gè)異常該怎么辦呢?
try-catch-finally捕獲異常
try{
// 將可能出現(xiàn)異常的代碼放在這里
}catch(要捕獲的異常類型 e){
// 對(duì)異常就可以正常處理,處理完成后,跳出try-catch結(jié)構(gòu),繼續(xù)執(zhí)行后序代碼
}catch(異常類型 e){
// 對(duì)異常進(jìn)行處理
}finally{
// 此處代碼一定會(huì)被執(zhí)行到
}
// 后序代碼
// 當(dāng)異常被捕獲到時(shí),異常就被處理了,這里的后序代碼一定會(huì)執(zhí)行
// 如果捕獲了,由于捕獲時(shí)類型不對(duì),那就沒有捕獲到,這里的代碼就不會(huì)被執(zhí)行
當(dāng)try中的代碼出現(xiàn)異常的時(shí)候,catch就會(huì)捕獲try中出現(xiàn)的異常,并且對(duì)應(yīng)的catch捕獲的異常類型是與try中拋出的異常類型一致,或者是try中拋出異常的基類,當(dāng)某個(gè)catch捕獲到了對(duì)應(yīng)的異常時(shí),如果catch中的代碼塊執(zhí)行完后,就會(huì)跳出其他的catch捕獲到finally(如果有),否則就到后續(xù)的代碼塊,也就是說catch只能捕獲到一種異常。
public static int length(String s) throws NullPointerException{
if(s == null) {
throw new NullPointerException("字符串引用指向null");
}
return s.length();
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String str = null;
int ret = 0;
try {
ret = length(str);
}catch(NullPointerException e) {
//e.printStackTrace將棧上出現(xiàn)的異常給打印出來
e.printStackTrace();
System.out.println("傳入的字符串為null,請(qǐng)重新輸入");
String tmp = scanner.nextLine();
ret = length(tmp);
}
System.out.println(ret);
}
注意事項(xiàng)
1. try塊內(nèi)拋出異常位置之后的代碼將不會(huì)被執(zhí)行
2. 如果拋出異常類型與catch時(shí)異常類型不匹配,即異常不會(huì)被成功捕獲,也就不會(huì)被處理,繼續(xù)往外拋,直到JVM收到后中斷程序----異常是按照類型來捕獲的。
3. try中可能會(huì)拋出多個(gè)不同的異常對(duì)象,則必須用多個(gè)catch來捕獲----即多種異常,多次捕獲。
4. 可以通過一個(gè)catch捕獲所有的異常,即多個(gè)異常,一次捕獲(不推薦)catch (ArrayIndexOutOfBoundsException | NullPointerException e) { ... }
5.如果異常之間具有父子關(guān)系,一定是子類異常在前catch,父類異常在后catch,否則語(yǔ)法錯(cuò)誤。
finally
finally中的代碼是一定會(huì)被執(zhí)行的,不管你的try中有沒有出現(xiàn)異常,就算你在catch捕獲異常并處理異常的時(shí)候return了,finally中的代碼也是會(huì)出現(xiàn)在程序結(jié)束之前。
finally通常被用在網(wǎng)絡(luò)連接數(shù)據(jù)庫(kù)連接、IO流等,在程序正?;蛘弋惓M顺鰰r(shí),必須要對(duì)資源進(jìn)行回收。另外,因?yàn)楫惓?huì)引發(fā)程序的跳轉(zhuǎn),可能導(dǎo)致有些語(yǔ)句執(zhí)行不到,finally就是用來解決這個(gè)問題的。
自定義異常類
當(dāng)我們平時(shí)登錄賬號(hào)的時(shí)候,如果用戶名或者密碼錯(cuò)誤的時(shí)候,我們又該拋出怎樣的異常呢?
Java中提供了非受查類異常NullPointerException(空指針異常)、IndexOutOfBoundsException(數(shù)組越界異常)、IllegalArguementException(無效參數(shù)異常)、ClassCastException(類型轉(zhuǎn)換異常)等。這些在我們的日常生活中顯然是不能完全覆蓋到的,所以就出現(xiàn)了自定義異常,我們可以自己定義異常。
當(dāng)我們自定義異常類的時(shí)候,我們需要繼承Exception類或者Exception的子RunTimeException,建議繼承RunTimeException。
自定義異常通常會(huì)繼承自 Exception 或者 RuntimeException
繼承自 Exception 的異常默認(rèn)是受查異常
繼承自 RuntimeException 的異常默認(rèn)是非受查異常文章來源:http://www.zghlxwxcb.cn/news/detail-444464.html
public class Main {
private static String name = "zhangsan";
private static String ps = "123456";
public static void login(String name,String ps) {
if(!Main.name.equals(name)) {
throw new NameException("用戶名錯(cuò)誤");
}
if(!Main.ps.equals(ps)) {
throw new PasswordException("密碼錯(cuò)誤");
}
}
public static void main1(String[] args) throws NameException,PasswordException{
Scanner scanner = new Scanner(System.in);
System.out.println("請(qǐng)輸入你的用戶名和密碼");
String name = scanner.nextLine();
String ps = scanner.nextLine();
try {
login(name,password);
}catch(NameException e) {
e.printStackTrace();
}catch(PasswordException e) {
e.printStackTrace();
}
}
class NameException extends RuntimeException {
public NameException(String message) {
super(message);
}
}
class PasswordException extends RuntimeException {
public PasswordException(String message) {
super(message);
}
}
文章來源地址http://www.zghlxwxcb.cn/news/detail-444464.html
到了這里,關(guān)于帶你深入理解Java異常的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!