Java 異常處理全解析:從基礎到自定義異常的實戰指南

Java 異常處理全解析:從基礎到自定義異常的實戰指南

一、Java 異常體系:Error 與 Exception 的本質區別

1. 異常體系核心架構

Java把異常當作對象來處理,并定義一個基類java.lang.Throwable作為所有異常的超類。

在Java API中已經定義了許多異常類,這些異常類分為兩大類,錯誤Error和異常Exception

Java 異常體系基于Throwable類,分為兩大分支:

Throwable
├─ Error(錯誤)
│  └─ 例:OutOfMemoryErrorStackOverflowError
└─ Exception(異常)├─ Checked Exception(編譯時異常)│  └─ 例:IOExceptionSQLException└─ Unchecked Exception(運行時異常)└─ 例:NullPointerExceptionArrayIndexOutOfBoundsException

在這里插入圖片描述

2.什么是異常以及異常的簡單分類

  • 異常指程序運行中出現的不期而至的各種狀況,如:文件找不到、網絡連接失敗、非法參數等。
  • 異常發生在程序運行期間,它影響了正常的程序執行流程。

要理解java異常處理是如何工作的,你需要掌握以下三種類型的異常Exception

  1. 檢查性異常:最具代表的檢查性異常是用戶錯誤或問題引起的異常,這是程序員無法預見的。例如要打開一個不存在文件時,一個異常就發生了,這些異常在編譯時不能被簡單地忽略。
  2. 運行時異常:運行時異常是可能被程序員避免的異常。與檢查性異常相反,運行時異常可以在編譯時被忽略。
  3. 錯誤Error: 錯誤不是異常,而是脫離程序員控制的問題。錯誤在代碼中通常被忽略。例如,當棧溢出時,一個錯誤就發生了,它們在編譯也檢查不到的。

3. Error vs Exception

Error和Exception的區別:Error通常是災難性的致命的錯誤,是程序無法控制和處理的,當出現這些異常時,Java虛擬機(JVM)一般會選擇終止線程;Exception通常情況下是可以被程序處理的,并且在程序中應該盡可能的去處理這些異常。

維度ErrorException
本質JVM 底層錯誤,不可恢復程序運行中的異常情況
處理方式無法捕獲,需重啟 JVM可捕獲處理或聲明拋出
典型場景內存溢出、類加載失敗空指針、數組越界、用戶輸入錯誤

4. Checked vs Unchecked 異常

  • Checked 異常

    • 必須顯式處理(捕獲或聲明拋出)
    • 示例:文件讀取時的FileNotFoundException
    try {FileReader reader = new FileReader("file.txt");
    } catch (FileNotFoundException e) {e.printStackTrace();
    }
    
  • Unchecked 異常

    • 無需強制處理(運行時檢查)
    • 示例:參數校驗失敗的IllegalArgumentException
    public void checkAge(int age) {if (age < 0) {throw new IllegalArgumentException("年齡不能為負數");}
    }
    

二、異常處理核心機制:捕獲與拋出

1. 異常捕獲語法(try-catch-finally)

try {// 可能拋出異常的代碼int result = 10 / 0; // 拋出ArithmeticException
} catch (ArithmeticException e) { // 捕獲具體異常System.out.println("錯誤原因:" + e.getMessage()); // 輸出:/ by zeroe.printStackTrace(); // 打印堆棧跟蹤信息
} catch (Exception e) { // 父類異常捕獲(需放在最后)// 通用異常處理
} finally {// 可選:無論是否異常都會執行(常用于資源釋放)System.out.println("執行finally塊");
}

2. 異常拋出關鍵字

throw(方法內拋出異常實例)
public static int divide(int a, int b) {if (b == 0) {throw new ArithmeticException("除數不能為0"); // 主動拋出異常}return a / b;
}
throws(方法聲明拋出異常)
public static void readFile(String path) throws FileNotFoundException {FileReader reader = new FileReader(path); // 聲明拋出Checked異常
}

3. 異常處理順序原則

  • 子類異常優先:具體異常(如FileNotFoundException)需寫在父類異常(如IOException)之前
  • finally 的絕對性:即使 try 塊中有return,finally 仍會執行(但返回值會被緩存)

4.本節狂神說筆記

package com.exception;public class Test {public static void main(String[] args) {int a = 10;int b = 0;//假設要捕獲多個異常: 從小到大!try {//try監控區域System.out.println(a/b);} catch (Error e) {//catch(想要捕獲的異常類型!)捕獲異常System.out.println("Error");} catch (Exception e) {System.out.println("Exception");} catch (Throwable e) {System.out.println("Throwable");} finally {//處理善后工作System.out.println("finally");}finally 可以不要finally, 假設I0,資源,關閉!}public void a(){b();}public void b(){a();}
}
package com.exception;public class Test2 {public static void main(String[] args) {int a = 1;int b = 0;//Ctrl Alt + Ttry {System.out.println(a/b);} catch (Exception e) {e.printStackTrace();//打印錯誤的棧信息} finally {}}
}
package com.exception;public class Test1 {public static void main(String[] args) {try {new Test1().test(1,0);} catch (ArithmeticException e) {e.printStackTrace();}}//假設這個方法中,處理不了這個異常。方法上拋出異常public void test(int a,int b) throws ArithmeticException{if(b == 0){//throw  throwsthrow new ArithmeticException();//主動的拋出異常,一般在方法中使用}}
}

三、自定義異常:打造業務專屬錯誤體系

使用Java內置的異常類可以描述在編程時出現的大部分異常情況。除此之外,用戶還可以自定義異常。用戶自定義異常類,只需繼承Exception類即可。

1. 自定義異常類步驟

  1. 創建自定義異常類。
  2. 在方法中通過throw關鍵字拋出異常對象。
  3. 如果在當前拋出異常的方法中處理異常,可以使用try-catch語句捕獲并處理;否則在方法的聲明處通過throws關鍵字指明要拋出給方法調用者的異常,繼續進行下一步操作。
  4. 在出現異常方法的調用者中捕獲并處理異常。
步驟 1:繼承 Exception 或 RuntimeException
// Checked異常(需顯式處理)
public class UserAgeException extends Exception {public UserAgeException(String message) {super(message); // 調用父類構造器}
}// Unchecked異常(運行時異常)
public class InvalidInputException extends RuntimeException {public InvalidInputException(String message) {super(message);}
}
步驟 2:在業務邏輯中拋出
public void validateUser(int age) throws UserAgeException {if (age < 18) {throw new UserAgeException("用戶年齡必須≥18歲"); // 拋出自定義Checked異常}
}

2. 異常處理最佳實踐

(1)異常信息規范
  • 包含足夠上下文:"用戶ID為" + userId + "的賬戶不存在"
  • 避免裸露捕獲Exception:應捕獲具體異常類型
(2)資源釋放最佳實踐
// JDK 7+ 自動資源管理(替代finally)
try (FileReader reader = new FileReader("file.txt")) {// 自動關閉資源(無需顯式finally)
} catch (IOException e) {// 處理文件讀取異常
}
(3)異常鏈使用
try {// 業務邏輯
} catch (ServiceException e) {throw new ControllerException("接口調用失敗", e); // 包裝異常鏈
}

3.實際應用中的經驗總結

  • 處理運行時異常時,采用邏輯去合理規避同時輔助 try-catch 處理
  • 在多重catch塊后面,可以加一個catch(Exception)來處理可能會被遺漏的異常
  • 對于不確定的代碼,也可以加上 try-catch,處理潛在的異常
  • 盡量去處理異常,切忌只是簡單地調用 printStackTrace()去打印輸出
  • 具體如何處理異常,要根據不同的業務需求和異常類型去決定
  • 盡量添加finally語句塊去釋放占用的資源

四、常見異常處理錯誤與解決方案

1. 空指針異常(NPE)

錯誤示例

String str = null;
int length = str.length(); // 拋出NullPointerException

解決方案

if (str != null) {int length = str.length();
} else {throw new IllegalArgumentException("字符串不可為null");
}

2. 未處理 Checked 異常

錯誤示例

public void readFile() {FileReader reader = new FileReader("file.txt"); // 編譯錯誤:未處理IOException
}

解決方案

// 方案1:捕獲處理
try { /* ... */ } catch (IOException e) { /* ... */ }// 方案2:聲明拋出
public void readFile() throws IOException { /* ... */ }

3. finally 中的 return 陷阱

錯誤示例

public static int testFinally() {try {return 1;} finally {return 2; // 最終返回2,覆蓋try中的return}
}

正確做法

public static int testFinally() {int result = 1;try {return result;} finally {result = 2; // 不建議在finally中使用return}
}

五、高頻面試題解析

1. Error 和 Exception 的根本區別?

  • Error 是 JVM 內部錯誤(如內存溢出),無法通過代碼處理,必須重啟應用
  • Exception 是程序運行中的異常,分為 Checked(編譯時檢查)和 Unchecked(運行時異常)

2. throw 和 throws 的區別?

關鍵字作用使用位置參數類型
throw拋出異常實例方法體內部異常對象
throws聲明方法可能拋出的異常類型方法簽名異常類列表

3. finally 塊一定會執行嗎?

  • 正常情況下一定會執行(包括 return 前執行)
  • 唯一例外:JVM 提前終止(如System.exit(0)

4. 自定義異常應該繼承哪個類?

  • 業務需要編譯時檢查:繼承Exception
  • 運行時異常(如參數校驗失敗):繼承RuntimeException

六、異常處理核心原則

  1. 具體捕獲:優先捕獲具體異常,避免使用寬泛的Exception
  2. 快速失敗:在方法入口校驗參數,盡早拋出異常
  3. 信息完整:異常信息需包含定位問題的關鍵數據(如用戶 ID、時間戳)
  4. 資源管理:使用try-with-resources自動釋放 IO、數據庫連接等資源

七、總結:構建健壯的異常處理體系

通過合理運用 Java 異常處理機制,開發者可以:

  1. 清晰區分系統錯誤與業務異常
  2. 通過捕獲特定異常實現精準的錯誤處理
  3. 利用自定義異常提升業務代碼的可讀性
    該繼承哪個類?
  • 業務需要編譯時檢查:繼承Exception
  • 運行時異常(如參數校驗失敗):繼承RuntimeException

六、異常處理核心原則

  1. 具體捕獲:優先捕獲具體異常,避免使用寬泛的Exception
  2. 快速失敗:在方法入口校驗參數,盡早拋出異常
  3. 信息完整:異常信息需包含定位問題的關鍵數據(如用戶 ID、時間戳)
  4. 資源管理:使用try-with-resources自動釋放 IO、數據庫連接等資源

七、總結:構建健壯的異常處理體系

通過合理運用 Java 異常處理機制,開發者可以:

  1. 清晰區分系統錯誤與業務異常
  2. 通過捕獲特定異常實現精準的錯誤處理
  3. 利用自定義異常提升業務代碼的可讀性
  4. 結合 finally 和 try-with-resources 確保資源安全釋放

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/78300.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/78300.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/78300.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

redis 數據類型新手練習系列——string類型

redis 數據類型 Redis 主要支持以下幾種數據類型&#xff1a; &#xff08;1&#xff09;string&#xff08;字符串&#xff09;: 基本的數據存儲單元&#xff0c;可以存儲字符串、整數或者浮點數。 &#xff08;2&#xff09;hash&#xff08;哈希&#xff09;:一個鍵值對集…

Android12源碼編譯及刷機

由于google的AOSP源碼拉取經常失敗&#xff0c;編譯還經常出現各種問題。這里根據香橙派Orange Pi 5 Plus&#xff08;Android12電視鏡像&#xff09;源碼進行編譯演示。 RK芯片的開發板可玩性很高&#xff0c;這里以電視版本android系統為例子&#xff0c;學習的同時還可以當…

從零實現 registry.k8s.io/pause:3.8 鏡像的導出與導入

以下是為 registry.k8s.io/pause:3.8 鏡像的導出與導入操作定制的完整教程&#xff0c;適用于 Kubernetes 集群中使用 containerd 作為容器運行時的場景。本教程包含詳細步驟、常見問題解析及注意事項。 從零實現 registry.k8s.io/pause:3.8 鏡像的導出與導入 背景說明 Kuber…

Redis和MQ的區別

redis是一個高性能的key-value數據庫&#xff0c;支持消息推送功能&#xff0c;可以當做一個輕量級的隊列服務器使用。 redis只是提供一個高性能的、原子操作內存鍵值隊&#xff0c;具有高速訪問能力&#xff0c;雖然可以做消息隊列的存儲&#xff0c;但不具備消息隊列的任何功…

Centos7系統防火墻使用教程

CentOS 7是一種常見的Linux操作系統&#xff0c;防火墻作為網絡安全的第一道防線&#xff0c;對于服務器的安全至關重要。本文將介紹CentOS 7系統中防火墻的使用教程&#xff0c;包括如何開啟、關閉、配置以及防火墻規則的添加和刪除。 一、查看防火墻狀態 在開始操作之前&am…

Uniapp:navigator(頁面跳轉)

目錄 一、基本概述二、屬性說明三、具體使用一、基本概述 頁面跳轉。該組件類似HTML中的<a>組件,但只能跳轉本地頁面。目標頁面必須在pages.json中注冊。 二、屬性說明 屬性名類型默認值說明平臺差異說明urlString應用內的跳轉鏈接,值為相對路徑或絕對路徑,如:“……

大疆機場及無人機上云(航線規劃、指令飛行...)

系統操作預覽&#xff1a; 包含一鍵起飛、指令飛行、云臺控制、變焦、航線規劃、空域規劃、成果數據展示、實時飛行模擬、任務派發等 大疆無人機飛控平臺&#xff08;航線規劃、機場3、私有化部署&#xff09;_嗶哩嗶哩_bilibili 2025-04-02 更新 start、 已支持大疆機場3。…

【運維】云端掌控:用Python和Boto3實現AWS資源自動化管理

《Python OpenCV從菜鳥到高手》帶你進入圖像處理與計算機視覺的大門! 解鎖Python編程的無限可能:《奇妙的Python》帶你漫游代碼世界 在云計算時代,AWS(Amazon Web Services)作為領先的云服務平臺,其資源管理的高效性對企業至關重要。本文深入探討如何利用Python的boto3…

Java ThreadLocal與內存泄漏

當我們利用 ThreadLocal 來管理數據時&#xff0c;我們不可避免地會面臨內存泄漏的風險。 原因在于 ThreadLocal 的工作方式。當我們在當前線程的 ThreadLocalMap 中存儲一個值時&#xff0c;一旦這個值不再需要&#xff0c;釋放它就變得至關重要。如果不這樣做&#xff0c;那么…

Linux之netlink(2)libnl使用介紹(1)

Linux之netlink(2)Libnl3使用介紹(1) Author&#xff1a;Onceday Date&#xff1a;2025年4月26日 漫漫長路&#xff0c;才剛剛開始… 全系列文章可查看專欄: Linux內核知識_Once-Day的博客-CSDN博客 本文翻譯自libnl3官方文檔&#xff1a;Netlink Library (libnl) 參考文檔…

深入理解TransmittableThreadLocal:原理、使用與避坑指南

一、ThreadLocal與InheritableThreadLocal回顧 在介紹TransmittableThreadLocal之前&#xff0c;我們先回顧一下Java中的ThreadLocal和InheritableThreadLocal。 1. ThreadLocal ThreadLocal提供了線程局部變量&#xff0c;每個線程都可以通過get/set訪問自己獨立的變量副本…

Linux下的I/O復用技術之epoll

I/O多路復用 指在單個線程或進程中&#xff0c;同時處理多個I/O操作的技術。 旨在提高程序處理多個并發I/O操作的能力&#xff0c;避免程序因等待某個I/O操作而被阻塞。在傳統的I/O模型中當程序進行I/O操作時(如讀取文件、接受網路數據等)&#xff0c;如果數據還未準備好&…

用 C 語言實現通用的冒泡排序算法

在日常編程中&#xff0c;排序算法是一個非常常見且重要的工具。雖然有許多排序算法可以選擇&#xff0c;但如果你需要一個能夠處理不同數據類型的排序算法&#xff0c;如何設計一個通用的排序算法呢&#xff1f;今天我們將實現一個通用的冒泡排序算法&#xff0c;支持不同數據…

C# 變量全解析:聲明、初始化與使用

在多用途的編程語言中&#xff0c;程序存取數據是一項基礎且關鍵的功能&#xff0c;而這一功能主要通過變量來實現。本文將全面深入地探討 C# 中的變量&#xff0c;包括變量的種類、聲明、初始化、自動初始化、多變量聲明以及如何使用變量的值。 變量概述 變量是一個名稱&…

Dify中的文本分詞處理技術詳解

Dify中的文本分詞處理技術詳解 引言核心架構概覽索引處理器工廠 文本分詞技術詳解基礎分詞器增強型遞歸字符分詞器固定分隔符文本分詞器遞歸分割算法 索引處理器中的分詞應用特殊索引處理器的分詞特點問答索引處理器父子索引處理器 分詞技術的應用場景技術亮點與優勢總結 引言 …

如何打包python程序為可執行文件

將 Python 程序打包為可執行文件是一個常見需求&#xff0c;尤其是在希望將應用程序分享給不具備 Python 環境的用戶時。以下是使用 PyInstaller 工具將 Python 程序打包為可執行文件的步驟。 步驟 1&#xff1a;安裝 PyInstaller 如果您還沒有安裝 PyInstaller&#xff0c;請…

美團Java后端二面面經!

場景題是面試的大頭&#xff0c;建議好好準備 Q. [美團]如何設計一個外賣訂單的并發扣減庫存系統&#xff1f; Q.[美團]為啥初始標記和重新標記需要STW&#xff1f; Q.[美團]騎手位置實時更新&#xff0c;如何保證高并發寫入&#xff1f; Q.[美團]訂單表數據量過大導致查詢…

在應用運維過程中,業務數據修改的證據留存和數據留存

在應用運維過程中,業務數據修改的證據留存和數據留存至關重要,以下是相關介紹: 一、證據留存 操作日志記錄 : 詳細記錄每一次業務數據修改的操作日志,包括操作人員、操作時間、修改內容、修改前后數據的對比等。例如,某公司業務系統中,操作日志會精確記錄員工小張在 2…

Eigen迭代求解器類

1. 迭代求解器核心類概覽 Eigen 提供多種迭代法求解稀疏線性方程組 AxbAxb&#xff0c;適用于大規模稀疏矩陣&#xff1a; 求解器類適用矩陣類型算法關鍵特性ConjugateGradient對稱正定&#xff08;SPD&#xff09;共軛梯度法&#xff08;CG&#xff09;高精度&#xff0c;內…