Java 最全異常講解

来源:https://www.cnblogs.com/deveypf/archive/2019/08/30/11437566.html
-Advertisement-
Play Games

1. 導引問題 實際工作中,遇到的情況不可能是非常完美的。比如:你寫的某個模塊,用戶輸入不一定符合你的要求、你的程式要打開某個文件,這個文件可能不存在或者文件格式不對,你要讀取資料庫的數據,數據可能是空的等。我們的程式再跑著,記憶體或硬碟可能滿了。等等。 軟體程式在運行過程中,非常可能遇到剛剛提到的這 ...


1. 導引問題

實際工作中,遇到的情況不可能是非常完美的。比如:你寫的某個模塊,用戶輸入不一定符合你的要求、你的程式要打開某個文件,這個文件可能不存在或者文件格式不對,你要讀取資料庫的數據,數據可能是空的等。我們的程式再跑著,記憶體或硬碟可能滿了。等等。

軟體程式在運行過程中,非常可能遇到剛剛提到的這些異常問題,我們叫異常,英文是:Exception,意思是例外。這些,例外情況,或者叫異常,怎麼讓我們寫的程式做出合理的處理。而不至於程式崩潰。

1.1 常見的錯誤:

  1. 用戶輸入錯誤
  2. 設備錯誤。硬體問題,比如印表機關掉、伺服器問題
  3. 物理限制。磁碟滿了
  4. 代碼限制。數組下標越界等

設計良好的程式應該在異常發生時提供處理這些錯誤的方法,使得程式不會因為異常的發生而終斷或產生不可預見的結果。

如果沒有異常處理機制,那麼:

1.2 兩個壞處:

1.邏輯代碼和錯誤處理代碼放一起!

2.程式員本身需要考慮的例外情況較複雜,對程式員本身要求較高!

異常機制就是當程式出現錯誤,程式如何安全退出的機制。

2. 異常(Exception)的概念

Java 如何處理異常?

第一個異常示例和解析:

public static void main(String[]args){
    int i=1/0;
}
執行上述代碼的異常信息如下:
Exception in thread"main"java.lang.ArithmeticException:/by zero at chuji.BubbleSort.main(BubbleSort.java:11)

Java 是採用面向對象的方式來處理異常的。

3. 處理過程

拋出異常:在執行一個方法時,如果發生異常,則這個方法生成代表該異常的一個對象,停止當前執行路徑,並把異常對象提交給 JRE。

捕獲異常:JRE 得到該異常後,尋找相應的代碼來處理該異常。JRE 在方法的調用棧中查找,從生成異常的方法開始回溯,直到找到相應的異常處理代碼為止。

4. 異常分類

JDK 中定義了很多異常類,這些類對應了各種各樣可能出現的異常事件,所有異常對象都是派生於 Throwable 類的一個實例。如果內置的異常類不能夠滿足需要,還可以創建自己的異常類。

異常類之間的關係圖

img

圖引用鏈接:https://www.cnblogs.com/hwaggLee/p/4509038.html

4.2 Error

Error 類層次描述了 Java 運行時系統內部錯誤和資源耗盡錯誤。這類錯誤是我們無法控制的,同時也是非常罕見的錯誤。所以在編程中,不去處理這類錯誤。

Error 表明系統 JVM 已經處於不可恢復的崩潰狀態中。我們不需要管他。

打開 JDK 的:java.lang.error,查看他的所有子類。

4.3 Exception

所有異常類的父類,其子類對應了各種各樣可能出現的異常事件。

4.4 Error 和 Exception 的區別

我開著車走在路上,一頭豬沖在路中間,我剎車。這叫一個異常。

我開著車在路上,發動機壞了,我停車,這叫錯誤。系統處於不可恢復的崩潰狀態。發動機什麼時候壞?我們普通司機能管嗎?不能。發動機什麼時候壞是汽車廠發動機製造商的事。

4.4.1 Runtime Exception

出現 RuntimeException 就一定是你的問題,可以不捕獲,因為小心點這些異常是可以避免的。 派生於RuntimeException 的異常。是一類特殊的異常,如被 0 除、數組下標超範圍等,其產生比較頻繁,處理麻煩,如果顯式的聲明或捕獲將會對程式可讀性和運行效率影響很大。因此由系統自動檢測並將它們交給預設的異常處理程式(用戶可不必對其處理)。這類異常通常是由編程錯誤導致的,因為只有小心點,這些異常都是可以避免的,所以在編寫程式時,並不要求必須使用異常處理機制來處理這類異常,所有這類異常都繼承自java.lang.RuntimeException。

常見的運行時異常有:

  1. ArithmeticException

    如試圖除以0

  2. NullPointerException

    當程式訪問一個空對象的成員變數或方法,訪問一個空數組的成員時發生

  3. ClassCastException

    發生多態後,如果強制轉化的並不是父類的子類時發生。編譯的時候可以通過,因為編譯的時候並不會檢查類型轉化的問題

  4. ArrayIndexOutOfBoundsException

    訪問的元素下表超過數組長度

  5. NumberFormatException

    數字格式異常!

心得:

大家平時在遇到 NullPointerException,也就是空指針的問題時,不要只記得百度,應該從報錯的地方去分析自己的代碼,因為空指針其實是你的代碼寫的不嚴謹造成的。空指針解決方案:Debug,看你對應的值是否為 null。

4.4.2 Checked Exception

所有不是 Runtime Exception 的異常,統稱為 Checked Exception,又被稱為“已檢查異常”。 這類異常的產生不是程式本身的問題,通常由外界因素造成的。為了預防這些異常產生時,造成程式的中斷或得到不正確的結果,Java 要求編寫可能產生這類異常的程式代碼時,一定要去做異常的處理。

編譯器將檢查是否為所有已檢查異常提供異常處理。

這一類異常,我們必須捕獲進行處理。

Java 語言將派生於 RuntimeException 類或 Error 類的所有異常稱為“未檢查異常”。

5. 異常的處理辦法之一:捕獲異常

5.1 try

try 語句指定了一段代碼,該段代碼就是一次捕獲並處理的範圍。在執行過程中,當任意一條語句產生異常時,就會跳過該段中後面的代碼。代碼中可能會產生並拋出一種或幾種類型的異常對象,它後面的catch語句要分別對這些異常做相應的處理

一個 try 語句必須帶有至少一個 catch 語句塊或一個 finally 語句塊 。

註:當異常處理的代碼執行結束以後,是不會回到try語句去執行尚未執行的代碼。

5.2 catch

1、每個 try 語句塊可以伴隨一個或多個 catch 語句,用於處理可能產生的不同類型的異常對象。

2.、常用方法:

toString ( )方法,顯示異常的類名和產生異常的原因
getMessage( ) 方法,只顯示產生異常的原因,但不顯示類名。
printStackTrace( ) 方法,用來跟蹤異常事件發生時堆棧的內容。

這些方法均繼承自 Throwable 類

3、catch 捕獲異常時的捕獲順序:

如果異常類之間有繼承關係,在順序安排上需註意。越是頂層的類(父類),越放在下麵。再不然就直接把多餘的catch 省略掉。

5.3 finally

有些語句,不管是否發生了異常,都必須要執行,那麼就可以把這樣的語句放到finally 語句塊中。

通常在 finally 中關閉程式塊已打開的資源,比如:文件流、釋放資料庫連接等。

5.4 典型代碼

public class TestException {
    public static void main(String[] args) {
        FileReader reader = null;
        try {
            reader = new FileReader("d:/a.txt");
            char temp = (char) reader.read();
            System.out.println("讀出的內容:" + temp);
        } catch (FileNotFoundException e) {
            System.out.println("文件沒有找到!!");
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("文件讀取錯誤!");
        } finally {
            System.out.println(" 不管有沒有異常,我肯定會被執行!");
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

5.5 try, catch,finally ,return 執行順序

執行順序:

1.執行 try,catch , 給返回值賦值

2.執行finally

3.return

6. 異常的處理辦法之二:聲明異常(throws 子句)

當 Checked Exception 產生時,不一定立刻處理它,可以再把異常 Throws 出去。

在方法中使用 try-chatch-finally 由這個方法處理異常。在一些情況下,當前方法並不需要處理髮生的異常,而是向上傳遞給調用它的方法處理。

如果一個方法中可能產生某種異常,但是並不能確定如何處理這種異常,則應根據異常規範在方法的首部聲明該方法可能拋出的異常。

如果一個方法拋出多個已檢查異常,就必須在方法的首部列出所有的異常,之間以逗號隔開。

6.1 典型代碼

public class FileTest {
    public static void main(String[] args) {
        try {
            readFile("d:/a.txt");
        } catch (FileNotFoundException e) {
            System.out.println("所需要的文件不存在!");
            e.printStackTrace();
        } catch (IOException e) {
            System.out.println("文件讀寫出錯誤!");
            e.printStackTrace();
        }
    }

    public static void readFile(String fileName) throws IOException {
        FileReader in = new FileReader(fileName);
        try {
            int tem = 0;
            tem = in.read();
            while (tem != -1) {
                System.out.println((char) tem);
                tem = in.read();
            }
        } finally {
            in.close();
        }
    }
}

6.2 方法重寫中聲明異常原則

子類聲明的異常範圍不能超過父類聲明的範圍。包含如下意思:

  1. 父類沒有聲明異常,子類也不能;
  2. 不可拋出原有方法拋出異常類的父類或上層類
  3. 拋出的異常類型的數目不可以比原有的方法拋出的還多(不是指個數)

7. 異常的處理辦法之三:手動拋出異常(throw子句)

Java 異常類對象除在程式執行過程中出現異常時由系統自動生成並拋出,也可根據需要手工創建並拋出。

在捕獲一個異常前,必須有一段代碼先生成異常對象並把它拋出。這個過程我們可以手工做,也可以由 JRE 來實現,但是他們調用的都是 throw 子句。

對於一個已經存在的異常類,拋出該類異常對象過程如下:

  1. 找到一個合適的異常類。

  2. 創建一個該類的對象。

  3. 將對象拋出

File f=new File("c:/tt.txt");
if(!f.exists()){
    try{
        throw new FileNotFoundException("File can't be found!");
    }catch(FileNotFoundException e){
        e.printStackTrace();
    }
}

8. 自定義異常

在程式中,可能會遇到任何標準異常類都沒有充分的描述清楚的問題,這種情況下可以創建自己的異常類。

怎麼做:

從 Exception 類或者它的子類派生一個子類即可

習慣上,定義的類應該包含 2 個構造器:一個是預設的構造器,另一個是帶有詳細信息的構造器。

典型代碼

class IllegalAgeException extends Exception {
    public IllegalAgeException() {
    }

    public IllegalAgeException(String msg) {
        super(msg);
    }
}

class Person {
    private String name;
    private int age;

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        if (age < 0) throw new IllegalAgeException("人的年齡不應該為負數");
        this.age = age;
    }

    public String toString() {
        return "name is " + name + " and age is " + age;
    }
}

public class MyExceptionTest {
    public static void main(String[] args) {
        Person p = new Person();
        try {
            p.setName("Lincoln");
            p.setAge(-1);
        } catch (IllegalAgeException e) {
            e.printStackTrace();
            System.exit(-1);
        }
        System.out.println(p);
    }
}

9. 使用異常機制建議

  1. 要避免使用異常處理代替錯誤處理,這樣會降低程式的清晰性,並且效率低下( Java 是採用面向對象的方式來處理異常的,所以也是會有一定的開銷)
  2. 只在異常情況下使用異常機制
  3. 不要進行小粒度的異常處理---應該將整個任務儘可能包裝在一個 Try 語句塊中
  4. 異常往往在低層拋出,高層處理(捕獲)

10. 總結

  • 一個圖
  • 五個關鍵字(try, catch, finally, throws, throw)
  • 先逮小的(子類),再逮大的(父類)
  • 異常和重寫的關係
  • 自定義異常

現在的喜歡,其實不是真正的喜歡,只是因為不瞭解而已,真正的喜歡,是建立在非常瞭解的基礎上。瞭解 java 基礎,喜歡上編程,不再迷茫。

喜歡文章的話可以掃描關註微信公眾號

img

搜索微信公眾號:Java知其所以然,可免費領取某課、Java 後端面經等資源,還有統一環境(教你怎麼配置一套開發環境)視頻領取。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ORM
    瞭解orm,先瞭解以下概念: 什麼是“持久化” 持久(Persistence),即把數據(如記憶體中的對象)保存到可永久保存的存儲設備中(如磁碟)。持久化的主要應用是將記憶體中的數據存儲在關係型的資料庫中,當然也可以存儲在磁碟文件中、XML數據文件中等等。 什麼是 “持久層” 持久層(Persisten ...
  • Django ORM 高性能查詢優化 一、QuerySet 1、可切片 使用Python 的切片語法來限制 記錄的數目 。它等同於SQL 的 和 子句。 不支持負的索引(例如 )。通常, 的切片返回一個新的 —— 它不會執行查詢。 2、可迭代 3、惰性查詢 是惰性執行的 —— 創建 不會帶來任何數據 ...
  • 基於Django的form模塊,快速的搭建註冊頁面,每個限制條件,都放在form模塊裡面,不單獨對每一項編寫標簽,使用模版的 for 迴圈來渲染。 首先設置form模塊 在blogs模塊下創建一個blogs_form.py文件 註意一點,需要引用django模塊下的forms模塊,還有widgets ...
  • pymysql安裝 ` pip install pymysql ` 鏈接資料庫、執行sql、關閉連接 增刪改查操作 插入數據 查找數據 ...
  • 提交的表單數據,常常要檢查有沒有敏感辭彙,如果有,需要給出提示,或者替換為*。 檢查、替換敏感辭彙有3種常用的方式 (1)在Servlet中操作。 (2)在Filter中先檢查。如果要替換敏感辭彙,request沒有setParameter()方法重新設置請求參數,怎麼向Servlet中傳遞替換後的 ...
  • 一、for迴圈練習 1.例子:輸入九九乘法表 二、while語句 1.while迴圈語句的語法結構: 2.while迴圈的執行原理: 先判斷表達式的結果;如果是true則執行迴圈體,執行完迴圈體,在進行布爾表達式的判斷,迴圈進行,直到如果結果為false;那麼就跳出該迴圈體 3.例子:死迴圈的編譯特 ...
  • 自動配置原理 配置文件到底能寫什麼?怎麼寫?自動配置原理; "配置文件能配置的屬性參照" 1、 自動配置原理: 1)、SpringBoot啟動的時候載入主配置類,開啟了自動配置功能 ==@EnableAutoConfiguration== 2)、@EnableAutoConfiguration 作用 ...
  • 一 簡單概念 RPC: ( Remote Procedure Call),遠程調用過程,是通過網路調用遠程電腦的進程中某個方法,從而獲取到想要的數據,過程如同調用本地的方法一樣. 阻塞IO :當阻塞I/O在調用InputStream.read()方法是阻塞的,一直等到數據到來時才返回,同樣Serv ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...