欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java?中的異常處理機(jī)制詳情介紹

 更新時(shí)間:2022年09月29日 09:08:25   作者:3A網(wǎng)絡(luò)_文文  
本篇文章主要介紹Java中的異常、如何處理函數(shù)拋出的異常、處理異常的原則、異常處理時(shí),性能開(kāi)銷(xiāo)大的地方,感興趣的小伙伴可以參考一下

前言:

Java 語(yǔ)言在設(shè)計(jì)之初就提供了相對(duì)完善的異常處理機(jī)制。 我們首先介紹一下 Java 中的異常。

介紹 Java 中的異常

異常是程序在運(yùn)行過(guò)程中出現(xiàn)的程序異常事件,異常會(huì)中斷正在執(zhí)行的正常指令流 。 Java 中的異常分為兩大類(lèi):Exception 和 Error。

下面是 Exception 和 Error 的類(lèi)定義:

public class Exception extends Throwable {}
public class Error extends Throwable {}

Exception 和 Error 都繼承了 Throwable 類(lèi),在 Java 中只有 Throwable 類(lèi)型的實(shí)例才可以被拋出(throw)或者被捕獲(catch)。 Exception 和 Error 體現(xiàn)了 Java 平臺(tái)設(shè)計(jì)者對(duì)不同異常情況的分類(lèi)。 下面我們逐一介紹 Error 和 Exception。

介紹 Error

Error 類(lèi)對(duì)象一般是由虛擬機(jī)生成并拋出,絕大部分的 Error 都會(huì)導(dǎo)致虛擬機(jī)自身處于不可恢復(fù)的狀態(tài),是程序無(wú)法控制和處理的。當(dāng)出現(xiàn) Error 時(shí),一般會(huì)選擇終止線程。 Error 中最常見(jiàn)的是虛擬機(jī)運(yùn)行錯(cuò)誤(VirtualMachineError 抽象類(lèi))。

虛擬機(jī)運(yùn)行錯(cuò)誤中最常見(jiàn)的有:

  • 內(nèi)存溢出(OutOfMemoryError):由于內(nèi)存不足,虛擬機(jī)沒(méi)有可分配的內(nèi)存了,垃圾回收器也不能釋放更多的內(nèi)存,那么虛擬機(jī)拋出 OutOfMemoryError
  • 棧溢出(StackOverflowError):如果一個(gè)線程已用的棧大小 超過(guò) 配置的允許最大的棧大小,那么虛擬機(jī)拋出 StackOverflowError

介紹 Exception

Exception 有兩種類(lèi)型「編譯時(shí)異常」和「運(yùn)行時(shí)異?!?/p>

  • 「編譯時(shí)異?!箤?duì)應(yīng) Java 的 Exception 類(lèi)
  • 「運(yùn)行時(shí)異常」對(duì)應(yīng) Java 的 RuntimeException 類(lèi)(RuntimeException 類(lèi)繼承 Exception 類(lèi) )

下面是 Exception、RuntimeException 類(lèi)的定義:

public class Exception extends Throwable {}
public class RuntimeException extends Exception {}

對(duì)于「運(yùn)行時(shí)異常」,我們?cè)诰帉?xiě)代碼的時(shí)候,可以不用主動(dòng)去 try-catch 捕獲(不強(qiáng)制要求),編譯器在編譯代碼的時(shí)候,并不會(huì)檢查代碼是否有對(duì)運(yùn)行時(shí)異常做了處理。 相反,對(duì)于「編譯時(shí)異?!?,我們?cè)诰帉?xiě)代碼的時(shí)候,必須主動(dòng)去 try-catch 獲取 或者 在函數(shù)定義中聲明向上拋出異常(throws),否則編譯就會(huì)報(bào)錯(cuò)。

所以:

  • 「運(yùn)行時(shí)異?!挂步凶鞣鞘軝z異常(Unchecked Exception)
  • 「編譯時(shí)異常」也叫作受檢異常(Checked Exception)

在函數(shù)拋出異常的時(shí)候,,我們?cè)撛趺刺幚砟??是吞掉還是向上拋出? 如果選擇向上拋出,我們應(yīng)該選擇拋出哪種類(lèi)型的異常呢?是受檢異常還是非受檢異常? 我們下文會(huì)對(duì)此介紹。

常見(jiàn)的編譯時(shí)異常有:

  • FileNotFoundException:當(dāng)嘗試打開(kāi)由指定路徑表示的文件失敗時(shí)拋出
  • ClassNotFoundException:當(dāng)應(yīng)用程序嘗試通過(guò)其字符串名稱加載類(lèi)時(shí)拋出,以下三種方法加載
    • Class.forName(java.lang.String)
    • ClassLoader.findSystemClass(java.lang.String)
    • ClassLoader.loadClass(java.lang.String, boolean)

常見(jiàn)的運(yùn)行時(shí)異常有:

  • 非法參數(shù)異常(IllegalArgumentException):當(dāng)傳入了非法或不正確的參數(shù)時(shí)拋出
  • 空指針異常(NullPointerException):當(dāng)在需要對(duì)象的情況下使用了 null 時(shí)拋出。
  • 下標(biāo)訪問(wèn)越界異常(IndexOutOfBoundsException):當(dāng)某種索引(例如數(shù)組,字符串或向量)的索引超出范圍時(shí)拋出。
  • 類(lèi)型轉(zhuǎn)換異常(ClassCastException):當(dāng)嘗試將對(duì)象轉(zhuǎn)換為不是實(shí)例的子類(lèi)時(shí)拋出。
  • 運(yùn)算異常(ArithmeticException):運(yùn)算條件出現(xiàn)異常時(shí)拋出。例如,“除以零” 的整數(shù)。

Java 異常類(lèi)的結(jié)構(gòu)

如何處理函數(shù)拋出的異常

在函數(shù)拋出異常的時(shí)候,我們?cè)撛趺刺幚砟兀渴峭痰暨€是向上拋出? 如果選擇向上拋出,我們應(yīng)該選擇拋出哪種類(lèi)型的異常呢?是受檢異常還是非受檢異常? 下面我們就對(duì)此介紹。

吞掉 or 拋出

在函數(shù)拋出異常的時(shí)候,我們?cè)撛趺刺幚恚渴峭痰暨€是向上拋出?

總結(jié)一下,在函數(shù)拋出異常的時(shí)候,感興趣的可以自己部署一套相關(guān)的環(huán)境自己嘗試練習(xí)下。

  • 直接吞掉
  • 原封不動(dòng)地 re-throw
  • 包裝成新的異常 re-throw

直接吞掉。具體的代碼示例如下所示:

public void func1() throws Exception1 {
    // ...
}

public void func2() {
    //...
    try {
        func1();
    } catch (Exception1 e) {
        //吐掉:try-catch打印日志
        log.warn("...", e);
    }
    //...
}

原封不動(dòng)地 re-throw。具體的代碼示例如下所示:

public void func1() throws Exception1 {
    // ...
}

//原封不動(dòng)的re-throw Exception1
public void func2() throws Exception1 {
    //...
    func1();
    //...
}

包裝成新的異常 re-throw。具體的代碼示例如下所示:

public void func1() throws Exception1 {
    // ...
}
public void func2() throws Exception2 {
    //...
    try {
        func1();
    } catch (Exception1 e) {
        // wrap成新的Exception2然后re-throw
        throw new Exception2("...", e);
    }
    //...
}

當(dāng)我們面對(duì)函數(shù)拋出異常的時(shí)候,應(yīng)該選擇上面的哪種處理方式呢?我總結(jié)了下面三個(gè)參考原則:

  • 如果 func1 () 拋出的異常是可以恢復(fù),且 func2 () 的調(diào)用方并不關(guān)心此異常,我們完全可以在 func2 () 內(nèi)將 func1 () 拋出的異常吞掉;
  • 如果 func1 () 拋出的異常對(duì) func2 () 的調(diào)用方來(lái)說(shuō),也是可以理解的、關(guān)心的 ,并且在業(yè)務(wù)概念上有一定的相關(guān)性,我們可以選擇直接將 func1 拋出的異常 re-throw;
  • 如果 func1 () 拋出的異常太底層,對(duì) func2 () 的調(diào)用方來(lái)說(shuō),缺乏背景去理解、且業(yè)務(wù)概念上無(wú)關(guān),我們可以將它重新包裝成調(diào)用方可以理解的新異常,然后 re-throw。

應(yīng)該選擇上面的哪種處理方式,總結(jié)來(lái)說(shuō)就是從以下兩個(gè)方面進(jìn)行判斷:

  • 函數(shù) 1 拋出的異常是否可以恢復(fù)
  • 函數(shù) 1 拋出的異常對(duì)于 函數(shù) 2 的調(diào)用方來(lái)說(shuō)是否可以理解、關(guān)心、業(yè)務(wù)概念相關(guān)

總之,是否往上繼續(xù)拋出,要看上層代碼是否關(guān)心這個(gè)異常。關(guān)心就將它拋出,否則就直接吞掉。 是否需要包裝成新的異常拋出,看上層代碼是否能理解這個(gè)異常、是否業(yè)務(wù)相關(guān)。如果能理解、業(yè)務(wù)相關(guān)就可以直接拋出,否則就封裝成新的異常拋出。

對(duì)于處理函數(shù)拋出的異常,我們需要注意:

  • 如果選擇吞掉函數(shù)拋出的異常的話,我們必須把異常輸出到日志系統(tǒng),方便后續(xù)診斷。
  • 如果把異常輸出到日志系統(tǒng)時(shí),我們?cè)诒WC診斷信息足夠的同時(shí),也要考慮避免包含敏感信息,因?yàn)槟菢涌赡軐?dǎo)致潛在的安全問(wèn)題。

如果我們看 Java 的標(biāo)準(zhǔn)類(lèi)庫(kù),你可能注意到類(lèi)似 java.net.ConnectException,出錯(cuò)信息是類(lèi)似 “Connection refused (Connection refused)”,而不包含具體的機(jī)器名、IP、端口等,一個(gè)重要考量就是信息安全。 類(lèi)似的情況在日志中也有,比如,用戶數(shù)據(jù)一般是不可以輸出到日志里面的。

受檢異常 or 非受檢異常

在函數(shù)拋出異常的時(shí)候,如果選擇向上拋出,我們應(yīng)該選擇拋出哪種類(lèi)型的異常呢?是受檢異常還是非受檢異常?

對(duì)于代碼 bug(比如下標(biāo)訪問(wèn)越界、空指針)以及不可恢復(fù)的異常(比如數(shù)據(jù)庫(kù)連接失?。?,即便我們捕獲了,也做不了太多事情,我們希望程序能 fail-fast,所以,我們傾向于使用非受檢異常,將程序終止掉。 對(duì)于可恢復(fù)異常、業(yè)務(wù)異常,比如提現(xiàn)金額大于余額的異常,我們更傾向于使用受檢異常,明確告知調(diào)用者需要捕獲處理。

處理異常的原則

盡量不要捕獲通用異常

盡量不要捕獲類(lèi)似 Exception 這樣的通用異常,而應(yīng)該捕獲特定異常(盡量縮小捕獲的異常范圍)。

下面舉例說(shuō)明,實(shí)例代碼如下:

try {
    // 業(yè)務(wù)代碼
    // …
    Thread.sleep(1000L);
} catch (Exception e) {
    // Ignore it
}

對(duì)于 Thread.sleep () 函數(shù)拋出的 InterruptedException,我們不應(yīng)該捕獲 Exception 通用異常,而應(yīng)該捕獲 InterruptedException 這樣的特定異常。

這是因?yàn)槲覀円WC程序不會(huì)捕獲到我們不希望捕獲的異常。比如,我們更希望 RuntimeException 導(dǎo)致線程終止,而不是被捕獲。

不要生吞異常

不要生吞(swallow)異常,盡量把異常信息記錄到日志系統(tǒng)中。 這是異常處理中要特別注意的事情,因?yàn)樯坍惓:芸赡軙?huì)導(dǎo)致難以診斷的詭異情況。 如果我們沒(méi)有把異常拋出,也沒(méi)有把異常記錄到日志系統(tǒng),程序可能會(huì)在后續(xù)出現(xiàn)難以排查的 bug。沒(méi)人能夠輕易判斷究竟是哪里拋出了異常,以及是什么原因產(chǎn)生了異常。

再來(lái)看一段代碼:

try {
    // 業(yè)務(wù)代碼
    // …
} catch (IOException e) {
    e.printStackTrace();
}

這段代碼作為一段實(shí)驗(yàn)代碼,是沒(méi)有任何問(wèn)題的,但是在產(chǎn)品代碼中,通常都不允許這樣處理。 你先思考一下這是為什么呢? 我們先來(lái)看看 printStackTrace () 的文檔,開(kāi)頭就是 “Prints this throwable and its backtrace to the standard error stream”。問(wèn)題就在這里,在稍微復(fù)雜一點(diǎn)的生產(chǎn)系統(tǒng)中,標(biāo)準(zhǔn)出錯(cuò)(STERR)不是個(gè)合適的輸出選項(xiàng),因?yàn)槟愫茈y判到底輸出到哪里去了。尤其是對(duì)于分布式系統(tǒng),如果發(fā)生異常,但是無(wú)法找到堆棧軌跡(stacktrace),這純屬是為診斷設(shè)置障礙。 所以,最好使用產(chǎn)品日志,詳細(xì)地將異常記錄到日志系統(tǒng)里。

異常處理時(shí),性能開(kāi)銷(xiāo)大的地方

我們從性能角度來(lái)審視一下 Java 的異常處理機(jī)制,這里有兩個(gè)性能開(kāi)銷(xiāo)相對(duì)大的地方:

  • try-catch 代碼段會(huì)產(chǎn)生額外的性能開(kāi)銷(xiāo),或者換個(gè)角度說(shuō),它往往會(huì)影響 JVM 對(duì)代碼進(jìn)行優(yōu)化,所以建議僅捕獲有必要的代碼段,盡量不要一個(gè)大的 try 包住整段的代碼;
  • Java 每實(shí)例化一個(gè) Exception,都會(huì)對(duì)當(dāng)時(shí)的棧進(jìn)行快照,這是一個(gè)相對(duì)比較重的操作。如果實(shí)例化 Exception 發(fā)生的非常頻繁,這個(gè)開(kāi)銷(xiāo)可就不能被忽略了。

當(dāng)我們的服務(wù)出現(xiàn)反應(yīng)變慢、吞吐量下降的時(shí)候,檢查發(fā)生最頻繁的 Exception 也是一種思路。

到此這篇關(guān)于Java 中的異常處理機(jī)制詳情介紹的文章就介紹到這了,更多相關(guān)Java 異常處理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java數(shù)據(jù)導(dǎo)入功能之讀取Excel文件實(shí)例

    Java數(shù)據(jù)導(dǎo)入功能之讀取Excel文件實(shí)例

    這篇文章主要介紹了Java數(shù)據(jù)導(dǎo)入功能之讀取Excel文件實(shí)例,本文給出了jar包的下載地址以及讀取Excel文件的代碼實(shí)例,需要的朋友可以參考下
    2015-06-06
  • java利用DFA算法實(shí)現(xiàn)敏感詞過(guò)濾功能

    java利用DFA算法實(shí)現(xiàn)敏感詞過(guò)濾功能

    在最近的開(kāi)發(fā)中遇到了敏感詞過(guò)濾,便去網(wǎng)上查閱了很多敏感詞過(guò)濾的資料,在這里也和大家分享一下自己的理解。下面這篇文章主要給大家介紹了關(guān)于java利用DFA算法實(shí)現(xiàn)敏感詞過(guò)濾功能的相關(guān)資料,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-06-06
  • JAVA MyBatis入門(mén)學(xué)習(xí)過(guò)程記錄

    JAVA MyBatis入門(mén)學(xué)習(xí)過(guò)程記錄

    MyBatis是一個(gè)支持普通SQL查詢,存儲(chǔ)過(guò)程和高級(jí)映射的優(yōu)秀持久層框架。這篇文章主要介紹了mybatis框架入門(mén)學(xué)習(xí)教程,需要的朋友可以參考下,希望能幫助到你
    2021-06-06
  • SpringMVC中DispatcherServlet的HandlerMapping詳解

    SpringMVC中DispatcherServlet的HandlerMapping詳解

    這篇文章主要介紹了SpringMVC中DispatcherServlet的HandlerMapping詳解,上回說(shuō)的Handler,我們說(shuō)是處理特定請(qǐng)求的,也就是說(shuō),不是所有的請(qǐng)求都能處理,那么問(wèn)題來(lái)了,我們?cè)踔滥膫€(gè)請(qǐng)求是由哪個(gè)Handler處理的呢,需要的朋友可以參考下
    2023-10-10
  • SpringBoot整合Docker實(shí)現(xiàn)一次構(gòu)建到處運(yùn)行的操作方法

    SpringBoot整合Docker實(shí)現(xiàn)一次構(gòu)建到處運(yùn)行的操作方法

    本文講解的是 SpringBoot 引入容器化技術(shù) Docker 實(shí)現(xiàn)一次構(gòu)建到處運(yùn)行,包括鏡像構(gòu)建、Docker倉(cāng)庫(kù)搭建使用、Docker倉(cāng)庫(kù)可視化UI等內(nèi)容,需要的朋友可以參考下
    2022-10-10
  • netty?pipeline中的inbound和outbound事件傳播分析

    netty?pipeline中的inbound和outbound事件傳播分析

    這篇文章主要為大家介紹了netty?pipeline中的inbound和outbound事件傳播分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • IDEA使用SequenceDiagram插件繪制時(shí)序圖的方法

    IDEA使用SequenceDiagram插件繪制時(shí)序圖的方法

    這篇文章主要介紹了IDEA使用SequenceDiagram插件繪制時(shí)序圖的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • java注釋轉(zhuǎn)json插件開(kāi)發(fā)實(shí)戰(zhàn)詳解

    java注釋轉(zhuǎn)json插件開(kāi)發(fā)實(shí)戰(zhàn)詳解

    這篇文章主要為大家介紹了java注釋轉(zhuǎn)json插件開(kāi)發(fā)實(shí)戰(zhàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • springboot 集成支付寶支付的示例代碼

    springboot 集成支付寶支付的示例代碼

    這篇文章主要介紹了springboot 集成支付寶支付的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • Java類(lèi)加載連接和初始化原理解析

    Java類(lèi)加載連接和初始化原理解析

    這篇文章主要介紹了Java類(lèi)加載連接和初始化原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03

最新評(píng)論