Java異常架構(gòu)和異常關(guān)鍵字圖文詳解
Java異常簡(jiǎn)介
Java異常是Java提供的一種識(shí)別及響應(yīng)錯(cuò)誤的一致性機(jī)制。
Java異常機(jī)制可以使程序中異常處理代碼和正常業(yè)務(wù)代碼分離,保證程序代碼更加優(yōu)雅,并提高程序健壯性。
Java異常架構(gòu)
1. Throwable
Throwable 是 Java 語(yǔ)言中所有錯(cuò)誤與異常的超類。
Throwable 包含兩個(gè)子類:Error(錯(cuò)誤)和 Exception(異常),它們通常用于指示發(fā)生了異常情況。
Throwable 包含了其線程創(chuàng)建時(shí)線程執(zhí)行堆棧的快照,它提供了 printStackTrace() 等接口用于獲取堆棧跟蹤數(shù)據(jù)等信息。
2. Error(錯(cuò)誤)
定義:Error 類及其子類。程序中無(wú)法處理的錯(cuò)誤,表示運(yùn)行應(yīng)用程序中出現(xiàn)了嚴(yán)重的錯(cuò)誤。
特點(diǎn):此類錯(cuò)誤一般表示代碼運(yùn)行時(shí) JVM 出現(xiàn)問(wèn)題。通常有 Virtual
MachineError(虛擬機(jī)運(yùn)行錯(cuò)誤)、NoClassDefFoundError(類定義錯(cuò)誤)
等。比如 OutOfMemoryError:內(nèi)存不足錯(cuò)誤;StackOverflowError:棧溢出錯(cuò)誤。此類錯(cuò)誤發(fā)生時(shí),JVM 將終止線程。這些錯(cuò)誤是不受檢異常,非代碼性錯(cuò)誤。因此,當(dāng)此類錯(cuò)誤發(fā)生時(shí),應(yīng)用程序不
應(yīng)該去處理此類錯(cuò)誤。按照J(rèn)ava慣例,我們是不應(yīng)該實(shí)現(xiàn)任何新的Error子類的!
3. Exception(異常)
程序本身可以捕獲并且可以處理的異常。Exception 這種異常又分為兩類:運(yùn)行時(shí)異常和編譯時(shí)異常。
運(yùn)行時(shí)異常
定義:RuntimeException 類及其子類,表示 JVM 在運(yùn)行期間可能出現(xiàn)的異常。
特點(diǎn):Java 編譯器不會(huì)檢查它。也就是說(shuō),當(dāng)程序中可能出現(xiàn)這類異常時(shí),倘若既"沒(méi)有通過(guò)throws聲明拋出它",也"沒(méi)有用try-catch語(yǔ)句捕獲它",還是會(huì)編譯通過(guò)。比如NullPointerException空指針異常、
ArrayIndexOutBoundException數(shù)組下標(biāo)越界異常、ClassCastException類型轉(zhuǎn)換異常、ArithmeticExecption算術(shù)異常。此類異常屬于不受檢異常,一般是由程序邏輯錯(cuò)誤引起的,在程序中可以選擇捕獲處理,也可以不處理。雖然 Java 編譯器不會(huì)檢查運(yùn)行時(shí)異常,但是我們也可以通過(guò) throws 進(jìn)行聲明拋
出,也可以通過(guò) try-catch 對(duì)它進(jìn)行捕獲處理。如果產(chǎn)生運(yùn)行時(shí)異常,則需要通過(guò)修改代碼來(lái)進(jìn)行避免。例如,若會(huì)發(fā)生除數(shù)為零的情況,則需要通過(guò)代碼避免該情況的發(fā)生!
RuntimeException 異常會(huì)由 Java 虛擬機(jī)自動(dòng)拋出并自動(dòng)捕獲(就算我們沒(méi)寫異常捕獲語(yǔ)句運(yùn)行時(shí)也會(huì)拋出錯(cuò)誤!?。祟惍惓5某霈F(xiàn)絕大數(shù)情況是代碼本身有問(wèn)題應(yīng)該從邏輯上去解決并改進(jìn)代碼。
編譯時(shí)異常
定義: Exception 中除 RuntimeException 及其子類之外的異常。
特點(diǎn): Java 編譯器會(huì)檢查它。如果程序中出現(xiàn)此類異常,比如
ClassNotFoundException(沒(méi)有找到指定的類異常),IOException(IO流異常),要么通過(guò)throws進(jìn)行聲明拋出,要么通過(guò)try-catch進(jìn)行捕獲處理,否則不能通過(guò)編譯。在程序中,通常不會(huì)自定義該類異常,而是直接使用系統(tǒng)提供的異常類。該異常我們必須手動(dòng)在代碼里添加捕獲語(yǔ)句來(lái)處理該異常。
4. 受檢異常與非受檢異常
Java 的所有異??梢苑譃槭軝z異常(checked exception)和非受檢異常
(unchecked exception)。
受檢異常
編譯器要求必須處理的異常。正確的程序在運(yùn)行過(guò)程中,經(jīng)常容易出現(xiàn)的、符合
預(yù)期的異常情況。一旦發(fā)生此類異常,就必須采用某種方式進(jìn)行處理。除
RuntimeException 及其子類外,其他的 Exception 異常都屬于受檢異常。編譯器會(huì)檢查此類異常,也就是說(shuō)當(dāng)編譯器檢查到應(yīng)用中的某處可能會(huì)此類異常時(shí),將會(huì)提示你處理本異常——要么使用try-catch捕獲,要么使用方法簽名中用 throws 關(guān)鍵字拋出,否則編譯不通過(guò)。
非受檢異常
編譯器不會(huì)進(jìn)行檢查并且不要求必須處理的異常,也就說(shuō)當(dāng)程序中出現(xiàn)此類異常時(shí),即使我們沒(méi)有try-catch捕獲它,也沒(méi)有使用throws拋出該異常,編譯也會(huì)正常通過(guò)。該類異常包括運(yùn)行時(shí)異常(RuntimeException極其子類)和錯(cuò)誤(Error)
Java異常關(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ā)生的異常。
• finally – finally語(yǔ)句塊總是會(huì)被執(zhí)行。它主要用于回收在try塊里打開(kāi)的物力資源(如數(shù)據(jù)庫(kù)連接、網(wǎng)絡(luò)連接和磁盤文件)。只有finally塊,執(zhí)行完成之后,才會(huì)回來(lái)執(zhí)行try或者catch塊中的return或者throw語(yǔ)句,如果finally中使用了 return或者throw等終止方法的語(yǔ)句,則就不會(huì)跳回執(zhí)行,直接停止。
• throw – 用于拋出異常。
• throws – 用在方法簽名中,用于聲明該方法可能拋出的異常。
Java異常處理
Java 通過(guò)面向?qū)ο蟮姆椒ㄟM(jìn)行異常處理,一旦方法拋出異常,系統(tǒng)自動(dòng)根據(jù)該異常對(duì)象尋找合適異常處理器(Exception Handler)來(lái)處理該異常,把各種不同的異常進(jìn)行分類,并提供了良好的接口。在 Java 中,每個(gè)異常都是一個(gè)對(duì)
象,它是 Throwable 類或其子類的實(shí)例。當(dāng)一個(gè)方法出現(xiàn)異常后便拋出一個(gè)異常對(duì)象,該對(duì)象中包含有異常信息,調(diào)用這個(gè)對(duì)象的方法可以捕獲到這個(gè)異常并可以對(duì)其進(jìn)行處理。Java 的異常處理是通過(guò) 5 個(gè)關(guān)鍵詞來(lái)實(shí)現(xiàn)的:try、 catch、throw、throws 和 finally。
在Java應(yīng)用中,異常的處理機(jī)制分為聲明異常,拋出異常和捕獲異常。
拋出異常
如果你覺(jué)得解決不了某些異常問(wèn)題,且不需要調(diào)用者處理,那么你可以拋出異常。 throw關(guān)鍵字作用是在方法內(nèi)部拋出一個(gè)Throwable類型的異常。任何Java代碼都可以通過(guò)throw語(yǔ)句拋出異常。
捕獲異常
程序通常在運(yùn)行之前不報(bào)錯(cuò),但是運(yùn)行后可能會(huì)出現(xiàn)某些未知的錯(cuò)誤,但是還不想直接拋出到上一級(jí),那么就需要通過(guò)try…catch…的形式進(jìn)行異常捕獲,之后根據(jù)不同的異常情況來(lái)進(jìn)行相應(yīng)的處理。
常見(jiàn)異常處理方式直接拋出異常
通常,應(yīng)該捕獲那些知道如何處理的異常,將不知道如何處理的異常繼續(xù)傳遞下去。傳遞異??梢栽诜椒ê灻幨褂?throws 關(guān)鍵字聲明可能會(huì)拋出的異常。
private static void readFile(String filePath) throws IOException { File file = new File(filePath); String result; BufferedReader reader = new BufferedReader(new FileReader(file)); while((result = reader.readLine())!=null) { System.out.println(result); } reader.close(); }
封裝異常再拋出
有時(shí)我們會(huì)從 catch 中拋出一個(gè)異常,目的是為了改變異常的類型。多用于在多系統(tǒng)集成時(shí),當(dāng)某個(gè)子系統(tǒng)故障,異常類型可能有多種,可以用統(tǒng)一的異常類型向外暴露,不需暴露太多內(nèi)部異常細(xì)節(jié)。
private static void readFile(String filePath) throws MyException { try { // code } catch (IOException e) { MyException ex = new MyException("read file failed."); ex.initCause(e); throw ex; } }
捕獲異常
在一個(gè) try-catch 語(yǔ)句塊中可以捕獲多個(gè)異常類型,并對(duì)不同類型的異常做出不同的處理
private static void readFile(String filePath) { try { // code } catch (FileNotFoundException e) { // handle FileNotFoundException } catch (IOException e){ // handle IOException } }
同一個(gè) catch 也可以捕獲多種類型異常,用 | 隔開(kāi)
private static void readFile(String filePath) { try { // code } catch (FileNotFoundException | UnknownHostException e) { // handle FileNotFoundException or UnknownHostException } catch (IOException e){ // handle IOException } }
自定義異常
習(xí)慣上,定義一個(gè)異常類應(yīng)包含兩個(gè)構(gòu)造函數(shù),一個(gè)無(wú)參構(gòu)造函數(shù)和一個(gè)帶有詳
細(xì)描述信息的構(gòu)造函數(shù)(Throwable 的 toString 方法會(huì)打印這些詳細(xì)信息,調(diào)試時(shí)很有用)
public class MyException extends Exception { public MyException(){ } public MyException(String msg){ super(msg); } // ... }
try-catch-finally
當(dāng)方法中發(fā)生異常,異常處之后的代碼不會(huì)再執(zhí)行,如果之前獲取了一些本地資源需要釋放,則需要在方法正常結(jié)束時(shí)和 catch 語(yǔ)句中都調(diào)用釋放本地資源的代碼,顯得代碼比較繁瑣,finally 語(yǔ)句可以解決這個(gè)問(wèn)題。
private static void readFile(String filePath) throws MyException { File file = new File(filePath); String result; BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(file)); while((result = reader.readLine())!=null) { System.out.println(result); } } catch (IOException e) { System.out.println("readFile method catch block."); MyException ex = new MyException("read file failed."); ex.initCause(e); throw ex; } finally { System.out.println("readFile method finally block."); if (null != reader) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } }
調(diào)用該方法時(shí),讀取文件時(shí)若發(fā)生異常,代碼會(huì)進(jìn)入 catch 代碼塊,之后進(jìn)入 finally 代碼塊;若讀取文件時(shí)未發(fā)生異常,則會(huì)跳過(guò) catch 代碼塊直接進(jìn)入 finally 代碼塊。所以無(wú)論代碼中是否發(fā)生異常,fianlly 中的代碼都會(huì)執(zhí)行。 若 catch 代碼塊中包含 return 語(yǔ)句,finally 中的代碼還會(huì)執(zhí)行嗎?將以上代碼 中的 catch 子句修改如下:
catch (IOException e) { System.out.println("readFile method catch block."); return; }
調(diào)用 readFile 方法,觀察當(dāng) catch 子句中調(diào)用 return 語(yǔ)句時(shí),finally 子句是 否執(zhí)行
readFile method catch block. readFile method finally block.
可見(jiàn),即使 catch 中包含了 return 語(yǔ)句,finally 子句依然會(huì)執(zhí)行。若 finally 中也包含 return 語(yǔ)句,finally 中的 return 會(huì)覆蓋前面的 return.
try-with-resource
上面例子中,finally 中的 close 方法也可能拋出 IOException, 從而覆蓋了原始異常。JAVA 7 提供了更優(yōu)雅的方式來(lái)實(shí)現(xiàn)資源的自動(dòng)釋放,自動(dòng)釋放的資源需要是實(shí)現(xiàn)了 AutoCloseable 接口的類。
private static void tryWithResourceTest(){ try (Scanner scanner = new Scanner(new FileInputStream("c:/abc"),"UTF8")){ // code } catch (IOException e){ // handle exception } }
try 代碼塊退出時(shí),會(huì)自動(dòng)調(diào)用 scanner.close 方法,和把 scanner.close 方法放在 finally 代碼塊中不同的是,若 scanner.close 拋出異常,則會(huì)被抑制,拋出的仍然為原始異常。被抑制的異常會(huì)由 addSusppressed 方法添加到原來(lái)的異常,如果想要獲取被抑制的異常列表,可以調(diào)用 getSuppressed 方法來(lái)獲取。
總結(jié)
到此這篇關(guān)于Java異常架構(gòu)和異常關(guān)鍵字的文章就介紹到這了,更多相關(guān)Java異常架構(gòu)和異常關(guān)鍵字內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot實(shí)現(xiàn)excel生成并且通過(guò)郵件發(fā)送的步驟詳解
實(shí)際開(kāi)發(fā)中,特別是在B端產(chǎn)品的開(kāi)發(fā)中,我們經(jīng)常會(huì)遇到導(dǎo)出excel的功能,更進(jìn)階一點(diǎn)的需要我們定期生成統(tǒng)計(jì)報(bào)表,然后通過(guò)郵箱發(fā)送給指定的人員,?今天要帶大家來(lái)實(shí)現(xiàn)的就是excel生成并通過(guò)郵件發(fā)送,需要的朋友可以參考下2023-10-10Java教程package和import訪問(wèn)控制的步驟詳解
這篇文章主要為大家介紹了Java教程package和import訪問(wèn)控制的步驟詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06Java實(shí)現(xiàn)學(xué)生管理系統(tǒng)詳解
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)學(xué)生管理系統(tǒng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2021-10-10詳解APP微信支付(java后臺(tái)_統(tǒng)一下單和回調(diào))
這篇文章主要介紹了APP微信支付(java后臺(tái)_統(tǒng)一下單和回調(diào)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05