[Java實戰經驗]異常處理最佳實踐

一些好的異常處理實踐。

目錄

  • 異常設計
    • 自定義異常
    • 為異常設計錯誤代碼(狀態碼)
    • 設計粒度
    • 全局異常處理
    • 異常日志信息保留
  • 異常處理時機
  • 資源管理
    • try-with-resources
    • 異常中的事務

異常設計

自定義異常

自定義異常設計,如業務異常定義BusinessException,設置一個基礎異常類,如XXAppBaseException(或就叫BaseException),然后讓各類異常繼承,如下:

public class UserException extends XXAppBaseException { ... }public class MapException extends XXAppBaseException { ... }

這里異常的劃分可以按照模塊、業務來區分,也可以分離業務代碼異常與技術代碼異常。

為異常設計錯誤代碼(狀態碼)

常見的異常代碼設計有HTTP的異常狀態碼,如404、500、502這種。
這樣做主要是便于日志分析和客戶端處理,很明顯,使用錯誤代碼做篩選能提升檢索效率、方便收集、自動化處理,且使用異常狀態碼來傳輸異常信息提升了信息傳輸與存儲效率。
等等……

設計粒度

自定義異常和異常錯誤代碼都是比較常見的操作,但是設計時需要考慮粒度。

一般有層級關系的設計更便于理解、維護。

在自定義異常中就是多層繼承關系,在異常錯誤碼中就是分層錯誤碼設計,如全局錯誤碼 > 模塊錯誤碼 > 具體錯誤碼

5xx—>5xxx->5xxxx

全局異常處理

使用Spring的@ControllerAdvice或類似機制統一處理異常。如:

/*** 全局異常處理器* * @author ruoyi*/
@RestControllerAdvice
public class GlobalExceptionHandler
{private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);/*** 權限校驗異常(ajax請求返回json,redirect請求跳轉頁面)*/@ExceptionHandler(AuthorizationException.class)public Object handleAuthorizationException(AuthorizationException e, HttpServletRequest request){String requestURI = request.getRequestURI();log.error("請求地址'{}',權限校驗失敗'{}'", requestURI, e.getMessage());if (ServletUtils.isAjaxRequest(request)){return AjaxResult.error(PermissionUtils.getMsg(e.getMessage()));}else{return new ModelAndView("error/unauth");}}/*** 請求方式不支持*/@ExceptionHandler(HttpRequestMethodNotSupportedException.class)public AjaxResult handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,HttpServletRequest request){String requestURI = request.getRequestURI();log.error("請求地址'{}',不支持'{}'請求", requestURI, e.getMethod());return AjaxResult.error(e.getMessage());}/*** 攔截未知的運行時異常*/@ExceptionHandler(RuntimeException.class)public AjaxResult handleRuntimeException(RuntimeException e, HttpServletRequest request){String requestURI = request.getRequestURI();log.error("請求地址'{}',發生未知異常.", requestURI, e);return AjaxResult.error(e.getMessage());}/*** 系統異常*/@ExceptionHandler(Exception.class)public AjaxResult handleException(Exception e, HttpServletRequest request){String requestURI = request.getRequestURI();log.error("請求地址'{}',發生系統異常.", requestURI, e);return AjaxResult.error(e.getMessage());}/*** 業務異常*/@ExceptionHandler(ServiceException.class)public Object handleServiceException(ServiceException e, HttpServletRequest request){log.error(e.getMessage(), e);if (ServletUtils.isAjaxRequest(request)){return AjaxResult.error(e.getMessage());}else{return new ModelAndView("error/service", "errorMessage", e.getMessage());}}
}

異常日志信息保留

在拋出異常時,建議連帶當前業務標識信息一起拋出(每一層日志拋出記錄標識),這樣方便排查問題。

異常處理時機

偶爾能看到一類將所有代碼塊都包起來的try-catch異常處理,這種代碼被稱為“防御式編程”的過度使用,會導致多種問題。

  1. 代碼可讀性降低:大量的異常處理代碼掩蓋了業務邏輯
  2. 異常信息丟失:每層都捕獲并重新拋出,可能丟失原始堆棧信息
  3. 難以維護:當需要修改異常處理邏輯時,需要修改多處代碼
  4. 性能影響:過多的try-catch會對性能產生輕微影響

異常處理應該在能夠正確響應的層級進行,如:

  1. 邊界層處理:如API層、用戶界面層、外部系統集成點
  2. 業務決策點處理:在能夠做出恢復決策的地方處理異常
  3. 資源管理點處理:在使用需要清理的資源的地方處理
// 不好的做法
public void badExceptionHandling() {try {// 獲取用戶User user = null;try {user = userRepository.findById(userId);} catch (Exception e) {log.error("Failed to get user", e);}// 獲取訂單Order order = null;try {order = orderRepository.findById(orderId);} catch (Exception e) {log.error("Failed to get order", e);}// 處理業務邏輯try {processOrder(user, order);} catch (Exception e) {log.error("Failed to process order", e);}} catch (Exception e) {log.error("Unexpected error", e);}
}
// 好的做法
public void goodExceptionHandling() {try {User user = userRepository.findById(userId);Order order = orderRepository.findById(orderId);processOrder(user, order);} catch (UserNotFoundException e) {// 有針對性地處理用戶不存在的情況log.warn("Order processing failed: User not found", e);notifyAdministrator(e);} catch (OrderNotFoundException e) {// 有針對性地處理訂單不存在的情況log.warn("Order processing failed: Order not found", e);notifyCustomer(userId, e);} catch (BusinessException e) {// 處理所有業務異常log.warn("Business rule violation during order processing", e);// 可能的補救措施} catch (Exception e) {// 處理所有其他未預期的異常log.error("Unexpected error during order processing", e);// 緊急措施}
}

資源管理

try-with-resources

使用try-with-resources自動關閉資源,防止泄露。為自己的資源類實現AutoCloseable接口,如:

public class ResourceLock implements AutoCloseable {// 獲取資源public ResourceLock() { /* 獲取鎖或資源 */ }@Overridepublic void close() { /* 釋放鎖或資源 */ }
}

使用finally和這個一樣。常規操作。

異常中的事務

在Spring框架中,默認情況運行時異常與嚴重問題會導致事務回滾,檢查型異常不會。

  • 運行時異常(unchecked):繼承自RuntimeException的異常,默認導致事務回滾
  • 檢查型異常(checked):繼承自Exception但不是RuntimeException的子類,默認不會導致事務回滾
  • Error:嚴重問題,如OutOfMemoryError,默認導致事務回滾

因此,我們需要注意異常對事務的影響。

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

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

相關文章

Makefile 入門指南

Makefile 入門指南 最簡單的例子 單文件編譯 假設我們有一個main.cpp文件,最簡單的Makefile如下: # 最簡單的單文件編譯 # 目標:依賴文件 main: main.cpp# 編譯命令g main.cpp -o main使用步驟: 將上述內容保存為名為Makefile的文件&…

PyTorch數據操作基礎教程:從張量創建到高級運算

本文通過示例代碼全面講解PyTorch中張量的基本操作,包含創建、運算、廣播機制、索引切片等核心功能,并提供完整的代碼和輸出結果。 1. 張量創建與基本屬性 import torch# 創建連續數值張量 x torch.arange(12, dtypetorch.float32) print("原始張…

【Redis】Redis中的常見數據類型(一)

文章目錄 前言一、Redis前置知識1. 全局命令2、數據結構和內部編碼3. 單線程架構 二、String 字符串1. 常見命令2. 計數命令3.其他命令4. 內部編碼5. 典型使用場景 三、Hash哈希1. 命令2.內部編碼3. 使用場景4. 緩存方式對比 結語 前言 Redis 提供了 5 種數據結構,…

Windows 中使用 `netstat` 命令查看端口占用

在 Windows 系統中,可以通過 netstat 命令來查看當前系統的網絡連接以及端口的占用情況。以下是關于該命令的具體說明: #### 使用方法 1. **查看所有端口及其狀態** 可以通過以下命令查看系統中的所有活動連接和監聽端口: bash net…

23種設計模式-結構型模式之裝飾器模式(Java版本)

Java 裝飾器模式(Decorator Pattern)詳解 🎁 什么是裝飾器模式? 裝飾器模式是一種結構型設計模式,允許向一個對象動態添加新的功能,而不改變其結構。 🧱 你可以想象成在原有功能上“包裹”一…

解決模擬器打開小紅書設備異常問題

解決模擬器打開小紅書設備異常問題 解決模擬器打開小紅書設備異常問題和無法打開問題 解決模擬器打開小紅書設備異常問題和無法打開問題 問題描述 最近有用戶反饋在模擬器上無法正常登錄和打開小紅書APP,系統提示"設備異常"錯誤。本文將詳細介紹如何通過…

論文閱讀:2025 arxiv AI Alignment: A Comprehensive Survey

總目錄 大模型安全相關研究:https://blog.csdn.net/WhiffeYF/article/details/142132328 AI Alignment: A Comprehensive Survey 人工智能對齊:全面調查 https://arxiv.org/pdf/2310.19852 https://alignmentsurvey.com/ https://www.doubao.com/cha…

精益數據分析(1/126):從《精益數據分析》探尋數據驅動增長之道

精益數據分析(1/126):從《精益數據分析》探尋數據驅動增長之道 在當今數字化時代,數據無疑是企業發展的關鍵驅動力,對于競爭激烈的程序化廣告行業更是如此。最近我在研讀《精益數據分析》這本書,收獲頗豐&…

第五節:React Hooks進階篇-如何用useMemo/useCallback優化性能

反模式:濫用導致的內存開銷React 19編譯器自動Memoization原理 React Hooks 性能優化進階:從手動到自動 Memoization (基于 React 18 及以下版本,結合 React 19 新特性分析) 一、useMemo/useCallback 的正確使用場景…

windows server C# IIS部署

1、添加IIS功能 windows server 2012、windows server 2016、windows server 2019 說明:自帶的是.net 4.5 不需要安裝.net 3.5 盡量使用 windows server 2019、2016高版本,低版本會出現需要打補丁的問題 2、打開IIS 3、打開iis應用池 .net 4.5 4、添…

Elasticsearch的Java客戶端庫QueryBuilders查詢方法大全

matchAllQuery 使用方法:創建一個查詢,匹配所有文檔。 示例:QueryBuilders.matchAllQuery() 注意事項:這種查詢不加任何條件,會返回索引中的所有文檔,可能會影響性能,特別是文檔數量很多時。 ma…

C#進階學習(六)單向鏈表和雙向鏈表,循環鏈表(下)循環鏈表

目錄 📊 鏈表三劍客:特性全景對比表 一、循環鏈表節點類 二、循環鏈表的整體設計框架 三、循環列表中的重要方法: (1)頭插法,在頭結點前面插入新的節點 (2)尾插法實現插入元素…

交換網絡基礎

學習目標 掌握交換機的基本工作原理 掌握交換機的基本配置 交換機的基本工作原理 交換機是局域網(LAN)中實現數據高效轉發的核心設備,工作在 數據鏈路層(OSI 模型第二層),其基本工作原理可概括為 “學習…

科學研究:怎么做

科研(科學研究)?? 是指通過系統化的方法,探索自然、社會或人文領域的未知問題,以發現新知識、驗證理論或解決實際問題的活動。它的核心是??基于證據的探索與創新??,旨在推動人類認知和技術的進步。 科研的核心要…

算法題(128):費解的開關

審題: 本題需要我們將多組測試用例中拉燈數小于等于6的最小拉燈數輸出,若拉燈數最小值仍大于6,則輸出-1 思路: 方法一:二進制枚舉 首先我們先分析一下基本特性: 1.所有的燈不可能重復拉:若拉的數…

MFC文件-屏幕錄像

下載本文件 本文件將獲取屏幕圖像數據的所有代碼整合到兩個文件中(ScreenRecorder.h和ScreenRecorder.cpp),使獲取屏幕圖像數據變得簡單。輸出IYUV視頻流。還可以獲取系統播放的聲音,輸出PCM音頻流。由于使用了MFC類,本…

0801ajax_mock-網絡ajax請求1-react-仿低代碼平臺項目

0 vite配置proxy代理 vite.config.ts代碼如下圖所示: import { defineConfig } from "vite"; import react from "vitejs/plugin-react";// https://vite.dev/config/ export default defineConfig({plugins: [react()],server: {proxy: {&qu…

JVM筆記【一】java和Tomcat類加載機制

JVM筆記一java和Tomcat類加載機制 java和Tomcat類加載機制 Java類加載 * loadClass加載步驟類加載機制類加載器初始化過程雙親委派機制全盤負責委托機制類關系圖自定義類加載器打破雙親委派機制 Tomcat類加載器 * 為了解決以上問題,tomcat是如何實現類加載機制的…

IP編址(來自YESLAB新網工的筆記)

上層協議類型 概念:通常指的是位于網絡層(如 IP 層)以上的協議類型,這些協議在數據傳輸時需要由網絡層(或更低層)協議承載。以 IP 協議為例,IP 報文頭部中的 協議字段(Protocol Fie…

SpringBoot學習(過濾器Filter。攔截器Interceptor。全局異常捕獲處理器GlobalExceptionHandler)(詳細使用教程)

目錄 一、過濾器Filter。 1.1定義與規范。 1.2工作原理與范圍。 1.3使用場景。 1.4 SpringBoot實現過濾器。&#xff08;Filter配置2種方式&#xff09; <1>注解配置(WebFilter、Order、ServletComponentScan)。 創建過濾器類。 啟用 Servlet 組件掃描。 <2>配置類…