Java常見異常全面梳理(含分類+含義+典型場景)
Java 異常體系核心分為 運(yùn)行時(shí)異常(RuntimeException,非受檢) 和 編譯時(shí)異常(Checked Exception 受檢),前者編譯期無需強(qiáng)制捕獲,由程序邏輯錯(cuò)誤導(dǎo)致;后者編譯期必須顯式捕獲/拋出,由外部環(huán)境(如IO、網(wǎng)絡(luò)、輸入)異常導(dǎo)致。此外,還有錯(cuò)誤(Error) 屬于JVM層面嚴(yán)重問題,通常無需程序處理。
區(qū)分「運(yùn)行時(shí)異常(預(yù)防為主)、受檢異常(強(qiáng)制處理)、JVM錯(cuò)誤(提前規(guī)避)」

一、運(yùn)行時(shí)異常(RuntimeException)—— 邏輯錯(cuò)誤主導(dǎo),預(yù)防優(yōu)先,捕獲兜底
繼承自java.lang.RuntimeException,編譯期無需強(qiáng)制處理,多由代碼邏輯不嚴(yán)謹(jǐn)導(dǎo)致,核心處理原則是通過嚴(yán)謹(jǐn)?shù)拇a邏輯從根源避免,僅對無法預(yù)防的場景做捕獲兜底。
1. NullPointerException(NPE)—— 開發(fā)最高頻異常
- 核心含義:調(diào)用空對象的方法/屬性、對空對象執(zhí)行集合/數(shù)組操作,或自動(dòng)拆箱空包裝類
- 典型場景:
Object obj = null; obj.toString();、Integer num = null; int n = num;、方法返回null未判空直接使用 - 標(biāo)準(zhǔn)處理方式(按優(yōu)雅度排序,從基礎(chǔ)到高級)
- 基礎(chǔ)方案:顯式判空,對所有可能為null的對象執(zhí)行非空校驗(yàn);
- 優(yōu)雅方案:Java 8+
Optional類,包裝可能為null的對象,避免手動(dòng)判空; - 校驗(yàn)方案:使用
Objects.requireNonNull()做參數(shù)/對象非空校驗(yàn),快速定位空指針源頭; - 開發(fā)規(guī)范:方法返回值盡量返回空集合/空對象(如
Collections.emptyList()),而非null,減少調(diào)用方判空成本。
- 核心代碼示例
// 1. 顯式判空
Object obj = getObj();
if (obj != null) {
obj.toString();
}
// 2. Optional優(yōu)雅處理(推薦,無嵌套判空)
Optional.ofNullable(getObj()).ifPresent(o -> o.toString()); // 僅當(dāng)非空時(shí)執(zhí)行
String res = Optional.ofNullable(getStr()).orElse("默認(rèn)值"); // 空則返回默認(rèn)值
// 3. 非空校驗(yàn)(參數(shù)/方法內(nèi)對象,快速定位問題)
public void doWork(User user) {
Objects.requireNonNull(user, "用戶對象不能為空");
Objects.requireNonNull(user.getName(), "用戶名不能為空");
}
- 避坑點(diǎn):切勿僅用
if (obj != null)做多層嵌套判空(會(huì)導(dǎo)致代碼臃腫),優(yōu)先使用Optional。
2. ArrayIndexOutOfBoundsException —— 數(shù)組操作專屬
- 核心含義:訪問數(shù)組的索引超出有效范圍(索引<0 或 索引>=數(shù)組長度)
- 典型場景:
int[] arr = new int[3]; arr[3] = 10;、循環(huán)遍歷數(shù)組時(shí)條件寫為i <= arr.length - 標(biāo)準(zhǔn)處理方式
- 核心原則:遍歷數(shù)組始終以
arr.length為邊界,循環(huán)條件用i < arr.length; - 根源規(guī)避:使用增強(qiáng)for循環(huán)遍歷數(shù)組,無需手動(dòng)操作索引,從源頭避免越界;
- 前置校驗(yàn):手動(dòng)操作索引時(shí),先校驗(yàn)索引合法性(
index >= 0 && index < arr.length)。
- 核心原則:遍歷數(shù)組始終以
- 核心代碼示例
int[] arr = {1,2,3};
// 1. 增強(qiáng)for循環(huán)(推薦,無索引操作)
for (int num : arr) {
System.out.println(num);
}
// 2. 手動(dòng)索引操作(前置校驗(yàn))
int index = 3;
if (index >= 0 && index < arr.length) {
System.out.println(arr[index]);
} else {
System.err.println("索引越界,合法索引0-" + (arr.length-1));
}
3. IndexOutOfBoundsException(含子類StringIndexOutOfBoundsException)
- 核心含義:訪問集合/字符串的索引超出有效范圍,是數(shù)組越界的「集合/字符串版」
- 典型場景:
List<String> list = new ArrayList<>(); list.get(0);、"java".substring(5) - 標(biāo)準(zhǔn)處理方式
- 集合操作:遍歷用增強(qiáng)for循環(huán),手動(dòng)獲取元素前校驗(yàn)
index < list.size()+集合非空(!list.isEmpty()); - 字符串操作:截取/獲取字符前校驗(yàn)
index < str.length()+字符串非空(!str.isBlank()); - 工具輔助:使用
org.apache.commons.lang3.StringUtils/CollectionUtils,避免原生方法的越界問題。
- 集合操作:遍歷用增強(qiáng)for循環(huán),手動(dòng)獲取元素前校驗(yàn)
- 核心代碼示例
List<String> list = Arrays.asList("a", "b");
String str = "java";
int index = 4;
// 集合安全獲取
if (!CollectionUtils.isEmpty(list) && index < list.size()) {
System.out.println(list.get(index));
}
// 字符串安全截取(Apache工具類,越界會(huì)返回空/原字符串,無異常)
String sub = StringUtils.substring(str, 0, index);
4. ClassCastException —— 類型轉(zhuǎn)換高頻異常
- 核心含義:將對象強(qiáng)制轉(zhuǎn)換為其實(shí)際運(yùn)行時(shí)類型并非所屬的類/接口(無繼承/實(shí)現(xiàn)關(guān)系)
- 典型場景:
Object obj = new Integer(10); String str = (String) obj;、泛型擦除后集合強(qiáng)轉(zhuǎn)元素 - 標(biāo)準(zhǔn)處理方式
- 前置判斷:轉(zhuǎn)換前用
instanceof校驗(yàn)對象實(shí)際運(yùn)行時(shí)類型,再執(zhí)行強(qiáng)轉(zhuǎn); - 簡化方案:Java 14+ 模式匹配,一步完成「類型判斷+強(qiáng)制轉(zhuǎn)換」,簡化代碼;
- 根源規(guī)避:集合操作強(qiáng)制指定泛型(如
List<String> list = new ArrayList<>()),編譯期攔截非目標(biāo)類型元素。
- 前置判斷:轉(zhuǎn)換前用
- 核心代碼示例
Object obj = new Integer(10);
// 1. 傳統(tǒng)方式:instanceof判斷+強(qiáng)轉(zhuǎn)
if (obj instanceof String) {
String str = (String) obj;
}
// 2. Java14+ 模式匹配(推薦,少一層代碼)
if (obj instanceof String str) {
System.out.println(str.length());
}
// 3. 泛型規(guī)避(從根源避免)
List<String> list = new ArrayList<>();
list.add("java");
// list.add(10); // 編譯期直接報(bào)錯(cuò),無法添加非String類型
5. InputMismatchException —— Scanner輸入專屬
- 核心含義:
java.util.Scanner讀取數(shù)據(jù)時(shí),輸入數(shù)據(jù)類型與預(yù)期讀取類型不兼容 - 典型場景:用
scanner.nextInt()讀整數(shù),用戶輸入字符串(“abc”)、小數(shù)(3.14) - 標(biāo)準(zhǔn)處理方式(核心:清空輸入緩沖區(qū),避免死循環(huán))
- 推薦方案:先判斷再讀取,使用Scanner的
hasNextXxx()系列方法匹配讀取方法(hasNextInt()對應(yīng)nextInt()); - 兜底方案:捕獲異常后,必須調(diào)用
scanner.next()清空緩沖區(qū)的無效數(shù)據(jù); - 萬能方案:先讀取原始字符串,再通過包裝類手動(dòng)轉(zhuǎn)換,配合
try-catch處理。
- 推薦方案:先判斷再讀取,使用Scanner的
- 核心代碼示例(推薦方案,無異常)
Scanner scanner = new Scanner(System.in);
int num = 0;
while (true) {
System.out.print("請輸入整數(shù):");
if (scanner.hasNextInt()) {
num = scanner.nextInt();
break; // 輸入合法,退出循環(huán)
} else {
System.err.println("輸入錯(cuò)誤,僅支持整數(shù)!");
scanner.next(); // 關(guān)鍵:清空緩沖區(qū)的無效數(shù)據(jù),避免死循環(huán)
}
}
6. ArithmeticException —— 數(shù)值計(jì)算錯(cuò)誤
- 核心含義:算術(shù)運(yùn)算中出現(xiàn)非法操作,整數(shù)除零/取模模數(shù)為0是最典型場景
- 典型場景:
int a = 10 / 0;、10 % 0(注:浮點(diǎn)數(shù)除零結(jié)果為Infinity,不會(huì)觸發(fā)此異常) - 標(biāo)準(zhǔn)處理方式
- 前置校驗(yàn):對除法/取模的除數(shù)/模數(shù)做非零校驗(yàn),從根源避免;
- 異常兜底:捕獲異常后,根據(jù)業(yè)務(wù)返回默認(rèn)值或拋出自定義提示,避免程序崩潰。
- 核心代碼示例
int a = 10, b = 0;
int res = 0;
// 前置校驗(yàn)(推薦)
if (b != 0) {
res = a / b;
} else {
System.err.println("除數(shù)不能為零");
res = 0; // 業(yè)務(wù)默認(rèn)值
}
// 異常兜底(無法提前校驗(yàn)的場景)
try {
res = a / b;
} catch (ArithmeticException e) {
System.err.println("計(jì)算失?。撼龜?shù)不能為零");
res = 0;
}
7. IllegalArgumentException —— 參數(shù)非法通用異常
- 核心含義:方法接收到不符合業(yè)務(wù)要求的非法參數(shù),是自定義方法參數(shù)校驗(yàn)的標(biāo)準(zhǔn)異常
- 典型場景:方法要求參數(shù)>0卻傳入-1、要求非空字符串卻傳入空串、
Collections.sort(null) - 標(biāo)準(zhǔn)處理方式
- 主動(dòng)拋出:方法入口處做參數(shù)校驗(yàn),參數(shù)不合法時(shí)主動(dòng)拋出該異常,并攜帶明確的錯(cuò)誤提示;
- 工具輔助:使用
Objects/Apache Commons工具類簡化參數(shù)校驗(yàn),避免重復(fù)代碼; - 框架適配:Spring項(xiàng)目可使用
@Valid/@NotBlank等注解做參數(shù)自動(dòng)校驗(yàn),無需手動(dòng)判斷。
- 核心代碼示例
// 手動(dòng)參數(shù)校驗(yàn)+主動(dòng)拋出異常(推薦,語義清晰)
public void setAge(int age) {
if (age < 0 || age > 150) {
throw new IllegalArgumentException("年齡必須在0-150之間,當(dāng)前值:" + age);
}
this.age = age;
}
// Spring項(xiàng)目注解校驗(yàn)(簡化代碼)
public void addUser(@Valid User user) {
// User類中:@NotBlank(message = "用戶名不能為空") private String name;
}
8. NumberFormatException —— 數(shù)值格式轉(zhuǎn)換錯(cuò)誤
- 核心含義:將非數(shù)值格式的字符串轉(zhuǎn)換為int/double/long等數(shù)值類型時(shí)觸發(fā)
- 典型場景:
Integer.parseInt("123a");、Double.parseDouble("3.14.5");、前端傳參非數(shù)值字符串后端直接轉(zhuǎn)換 - 標(biāo)準(zhǔn)處理方式
- 異常捕獲:轉(zhuǎn)換時(shí)通過
try-catch捕獲異常,返回業(yè)務(wù)默認(rèn)值或提示格式錯(cuò)誤; - 工具輔助:使用
org.apache.commons.lang3.math.NumberUtils,轉(zhuǎn)換失敗返回默認(rèn)值,無需手動(dòng)捕獲; - 前置校驗(yàn):轉(zhuǎn)換前通過正則表達(dá)式校驗(yàn)字符串是否為合法數(shù)值(如
^\\d+$匹配整數(shù))。
- 異常捕獲:轉(zhuǎn)換時(shí)通過
- 核心代碼示例
String str = "123a";
// 1. try-catch兜底
int num1 = 0;
try {
num1 = Integer.parseInt(str);
} catch (NumberFormatException e) {
System.err.println("數(shù)值格式錯(cuò)誤,默認(rèn)值為0");
}
// 2. NumberUtils工具類(推薦,簡化代碼)
int num2 = NumberUtils.toInt(str, 0); // 轉(zhuǎn)換失敗返回默認(rèn)值0
double num3 = NumberUtils.toDouble(str, 0.0);
9. ConcurrentModificationException —— 集合并發(fā)修改錯(cuò)誤
- 核心含義:單/多線程中,遍歷集合的同時(shí)執(zhí)行結(jié)構(gòu)性修改(增/刪/修改集合容量)
- 典型場景:增強(qiáng)for循環(huán)遍歷List時(shí)調(diào)用
list.remove()、多線程同時(shí)操作非線程安全集合(ArrayList/HashMap) - 標(biāo)準(zhǔn)處理方式(分單/多線程場景)
- 單線程:使用迭代器(Iterator) 遍歷并修改,調(diào)用
it.remove(),這是集合遍歷修改的標(biāo)準(zhǔn)方式; - 多線程:替換為線程安全集合(
CopyOnWriteArrayList替代ArrayList、ConcurrentHashMap替代HashMap); - 兜底方案:遍歷前將集合轉(zhuǎn)為數(shù)組,或遍歷過程中收集需要修改的元素,遍歷完成后統(tǒng)一處理。
- 單線程:使用迭代器(Iterator) 遍歷并修改,調(diào)用
- 核心代碼示例
List<String> list = new ArrayList<>();
list.add("a"); list.add("b"); list.add("c");
// 1. 單線程安全修改(迭代器)
Iterator<String> it = list.iterator();
while (it.hasNext()) {
if ("a".equals(it.next())) {
it.remove(); // 無異常,標(biāo)準(zhǔn)方式
}
}
// 2. 多線程安全集合(直接替換,無需修改業(yè)務(wù)代碼)
List<String> safeList = new CopyOnWriteArrayList<>();
Map<String, String> safeMap = new ConcurrentHashMap<>();
10. UnsupportedOperationException —— 不支持的操作
- 核心含義:調(diào)用了對象未實(shí)現(xiàn)/不支持的方法,多為只讀/固定長度對象的修改操作
- 典型場景:
Arrays.asList(arr).add(1);(該List為固定長度)、對Collections.unmodifiableList()執(zhí)行增刪 - 標(biāo)準(zhǔn)處理方式
- 根源規(guī)避:若需修改數(shù)組轉(zhuǎn)換的List,重新創(chuàng)建可修改集合(
new ArrayList<>(Arrays.asList(arr))); - 開發(fā)規(guī)范:使用集合前確認(rèn)其類型,避免對只讀集合執(zhí)行修改操作;
- 前置判斷:通過集合的
class判斷是否為可修改類型(兜底方案)。
- 根源規(guī)避:若需修改數(shù)組轉(zhuǎn)換的List,重新創(chuàng)建可修改集合(
- 核心代碼示例
String[] arr = {"a", "b"};
// 錯(cuò)誤:固定長度List,無法修改
// List<String> list = Arrays.asList(arr);
// 正確:重新創(chuàng)建可修改ArrayList
List<String> list = new ArrayList<>(Arrays.asList(arr));
list.add("c"); // 正常執(zhí)行
二、受檢異常(Checked Exception)—— 外部環(huán)境異常,強(qiáng)制處理,資源釋放
繼承自java.lang.Exception(非RuntimeException子類),編譯期必須通過try-catch捕獲或throws聲明拋出,多由程序外部環(huán)境異常導(dǎo)致(如文件不存在、網(wǎng)絡(luò)斷開),核心處理原則是強(qiáng)制捕獲處理,核心操作是「釋放資源+業(yè)務(wù)兜底」。
1. IOException(及子類)—— IO操作核心異常(最常用)
- 核心含義:所有IO操作的通用異常父類,子類覆蓋具體場景:
FileNotFoundException(文件不存在)、SocketException(網(wǎng)絡(luò)斷開)、EOFException(文件提前結(jié)束) - 典型場景:文件讀寫、流的打開/關(guān)閉、網(wǎng)絡(luò)數(shù)據(jù)傳輸、控制臺(tái)輸入流操作
- 標(biāo)準(zhǔn)處理方式(核心:保證IO資源100%釋放)
- 優(yōu)雅方案:Java 7+ try-with-resources 語法(自動(dòng)關(guān)閉實(shí)現(xiàn)
AutoCloseable接口的資源,替代finally,推薦); - 傳統(tǒng)方案:
try-catch-finally,在finally塊中手動(dòng)關(guān)閉資源(需判空,避免空指針); - 業(yè)務(wù)兜底:捕獲異常后記錄日志,返回友好的業(yè)務(wù)提示(如“文件讀取失敗”),避免暴露底層異常。
- 優(yōu)雅方案:Java 7+ try-with-resources 語法(自動(dòng)關(guān)閉實(shí)現(xiàn)
- 核心代碼示例(try-with-resources 自動(dòng)釋放資源,推薦)
// 流對象實(shí)現(xiàn)AutoCloseable,try代碼塊結(jié)束后自動(dòng)關(guān)閉,無需手動(dòng)finally
try (FileReader fr = new FileReader("test.txt");
BufferedReader br = new BufferedReader(fr)) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (FileNotFoundException e) {
System.err.println("業(yè)務(wù)提示:文件不存在,請檢查路徑");
log.error("文件讀取失敗,路徑:test.txt", e); // 記錄詳細(xì)日志(含堆棧)
} catch (IOException e) {
System.err.println("業(yè)務(wù)提示:文件讀取失敗");
log.error("文件讀寫異常", e);
}
- 關(guān)鍵子類:
FileNotFoundException(優(yōu)先捕獲,精準(zhǔn)定位文件問題)、SocketException(網(wǎng)絡(luò)IO,需增加重連邏輯)。
2. InterruptedException —— 線程中斷協(xié)作異常
- 核心含義:線程處于可中斷阻塞狀態(tài)時(shí),被其他線程調(diào)用
interrupt()中斷,是線程間的「協(xié)作中斷信號」(非錯(cuò)誤異常) - 典型場景:線程執(zhí)行
Thread.sleep()/Object.wait()/CountDownLatch.await()/Thread.join()時(shí)被中斷 - 關(guān)鍵特性:異常觸發(fā)后,JVM會(huì)自動(dòng)清除線程的中斷狀態(tài)(
isInterrupted()返回false),切勿空catch吞掉異常(并發(fā)編程大忌) - 標(biāo)準(zhǔn)處理方式(核心三原則:恢復(fù)狀態(tài)/釋放資源/優(yōu)雅終止,分3種場景)
- 工具方法場景:捕獲異常后恢復(fù)中斷狀態(tài)(
Thread.currentThread().interrupt())+ 向上拋出異常,讓上層調(diào)用方處理; - 線程入口場景:捕獲異常后立即釋放資源(關(guān)閉流/釋放鎖)+ 直接終止線程(
return); - 批量任務(wù)場景:恢復(fù)中斷狀態(tài) + 跳過當(dāng)前任務(wù),讓后續(xù)代碼檢測到中斷并處理。
- 工具方法場景:捕獲異常后恢復(fù)中斷狀態(tài)(
- 核心代碼示例(工具方法+線程入口,最常用)
// 場景1:工具方法(不負(fù)責(zé)線程生命周期,向上拋出)
public void doBlockingWork() throws InterruptedException {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢復(fù)中斷狀態(tài),讓上層感知
throw e; // 向上拋出
}
}
// 場景2:線程入口(最終處理,釋放資源+終止)
Thread worker = new Thread(() -> {
FileWriter writer = null;
try {
writer = new FileWriter("log.txt");
doBlockingWork(); // 調(diào)用工具方法
} catch (InterruptedException e) {
System.out.println("收到中斷請求,開始優(yōu)雅終止");
// 步驟1:釋放資源
if (writer != null) {
try { writer.close(); } catch (IOException ex) { log.error("資源釋放失敗", ex); }
}
// 步驟2:終止線程
return;
} catch (IOException e) {
log.error("IO異常", e);
}
});
worker.start();
worker.interrupt(); // 主線程觸發(fā)中斷
3. SQLException —— 數(shù)據(jù)庫JDBC操作專屬
- 核心含義:執(zhí)行數(shù)據(jù)庫操作(增刪改查、連接、關(guān)閉)時(shí)觸發(fā),覆蓋連接失敗、SQL語法錯(cuò)誤、表/字段不存在等場景
- 典型場景:數(shù)據(jù)庫地址/賬號密碼錯(cuò)誤、SQL語句拼寫錯(cuò)誤、操作不存在的表、連接池耗盡
- 標(biāo)準(zhǔn)處理方式(核心:資源釋放+事務(wù)回滾+隱藏敏感信息)
- 資源管理:使用try-with-resources自動(dòng)關(guān)閉
Connection/Statement/ResultSet(均實(shí)現(xiàn)AutoCloseable),避免數(shù)據(jù)庫連接泄漏; - 事務(wù)處理:異常時(shí)執(zhí)行事務(wù)回滾(
conn.rollback()),避免數(shù)據(jù)不一致; - 日志與提示:記錄詳細(xì)日志(含SQL語句、參數(shù)),返回通用業(yè)務(wù)提示(如“數(shù)據(jù)庫操作失敗”),避免暴露數(shù)據(jù)庫地址/賬號等敏感信息;
- 重試機(jī)制:對連接超時(shí)、網(wǎng)絡(luò)抖動(dòng)等臨時(shí)異常,增加重試邏輯(配合Guava Retryer/Spring Retry)。
- 資源管理:使用try-with-resources自動(dòng)關(guān)閉
- 核心代碼示例
String sql = "INSERT INTO user (name) VALUES (?)";
// try-with-resources 自動(dòng)關(guān)閉數(shù)據(jù)庫資源
try (Connection conn = DBUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
conn.setAutoCommit(false); // 關(guān)閉自動(dòng)提交,開啟事務(wù)
pstmt.setString(1, "test");
pstmt.executeUpdate();
conn.commit(); // 提交事務(wù)
} catch (SQLException e) {
// 事務(wù)回滾
if (conn != null) {
try { conn.rollback(); } catch (SQLException ex) { log.error("事務(wù)回滾失敗", ex); }
}
log.error("SQL執(zhí)行失敗,SQL:{}", sql, e); // 記錄詳細(xì)日志
System.err.println("業(yè)務(wù)提示:數(shù)據(jù)保存失敗,請稍后重試"); // 通用提示
}
4. ClassNotFoundException —— 類加載異常
- 核心含義:JVM在類加載過程中,無法找到指定全限定名的類文件(包名+類名)
- 典型場景:反射加載類時(shí)類名寫錯(cuò)(
Class.forName("com.test.User"))、項(xiàng)目依賴缺失、classpath未包含該類 - 標(biāo)準(zhǔn)處理方式
- 基礎(chǔ)排查:檢查類的全限定名是否拼寫正確(包名、類名大小寫);
- 環(huán)境檢查:確認(rèn)項(xiàng)目運(yùn)行時(shí)的classpath包含該類的class文件/依賴包;
- 異常處理:捕獲異常后記錄詳細(xì)日志(類名、classpath信息),返回明確的排查提示。
- 核心代碼示例
try {
Class<?> cls = Class.forName("com.test.User");
Object obj = cls.newInstance();
} catch (ClassNotFoundException e) {
log.error("類加載失敗,類名:com.test.User,請檢查類名/依賴", e);
System.err.println("系統(tǒng)異常:類加載失敗,請聯(lián)系開發(fā)人員");
} catch (InstantiationException | IllegalAccessException e) {
log.error("類實(shí)例化失敗", e);
}
5. ParseException —— 日期/字符串解析異常
- 核心含義:對日期、自定義格式字符串進(jìn)行解析/格式化時(shí),輸入格式與指定格式不匹配
- 典型場景:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); sdf.parse("2026/02/05") - 標(biāo)準(zhǔn)處理方式
- 根源規(guī)避:統(tǒng)一數(shù)據(jù)格式,前端傳參做格式限制(如日期僅允許yyyy-MM-dd);
- 優(yōu)雅方案:使用Java 8+ 新日期時(shí)間API(
LocalDate/DateTimeFormatter),線程安全且拋出更友好的DateTimeParseException(運(yùn)行時(shí)異常); - 異常捕獲:解析前校驗(yàn)輸入格式,捕獲異常后返回默認(rèn)值或友好提示。
- 核心代碼示例(推薦新日期API,替代傳統(tǒng)SimpleDateFormat)
String dateStr = "2026/02/05";
// 傳統(tǒng)方式(SimpleDateFormat,非線程安全)
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
Date date = sdf.parse(dateStr);
} catch (ParseException e) {
System.err.println("日期格式錯(cuò)誤,請按yyyy-MM-dd輸入");
}
// Java8+ 新日期API(推薦,線程安全,異常更友好)
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
try {
LocalDate date = LocalDate.parse(dateStr, formatter);
} catch (DateTimeParseException e) { // 運(yùn)行時(shí)異常,無需強(qiáng)制捕獲
System.err.println("日期格式錯(cuò)誤,請按yyyy-MM-dd輸入");
}
三、JVM錯(cuò)誤(Error)—— 系統(tǒng)層面嚴(yán)重問題,提前規(guī)避,無需處理
繼承自java.lang.Error,屬于JVM/系統(tǒng)層面的嚴(yán)重異常,程序無法捕獲和恢復(fù),一旦發(fā)生通常導(dǎo)致程序崩潰,核心處理原則是提前規(guī)避,通過代碼優(yōu)化/JVM調(diào)優(yōu)/環(huán)境配置防止發(fā)生,無需在代碼中手動(dòng)捕獲。
1. OutOfMemoryError(OOM)—— 內(nèi)存溢出
- 核心含義:JVM堆內(nèi)存、方法區(qū)、元空間等內(nèi)存區(qū)域耗盡,無法為新對象分配內(nèi)存
- 典型場景:無限循環(huán)創(chuàng)建大對象、集合存儲(chǔ)大量數(shù)據(jù)未清理(內(nèi)存泄漏)、JVM堆內(nèi)存設(shè)置過小(
-Xmx配置不合理)、靜態(tài)集合持有大量對象引用 - 標(biāo)準(zhǔn)規(guī)避方式
- 代碼優(yōu)化:及時(shí)釋放無用對象引用(如集合使用后清空、避免靜態(tài)集合存儲(chǔ)業(yè)務(wù)數(shù)據(jù)),排查內(nèi)存泄漏(使用MAT/JProfiler工具);
- JVM調(diào)優(yōu):合理設(shè)置堆內(nèi)存參數(shù)(
-Xms初始堆 =-Xmx最大堆,避免內(nèi)存頻繁擴(kuò)容,如-Xms2G -Xmx2G),調(diào)整元空間大?。?code>-XX:MetaspaceSize=256M); - 業(yè)務(wù)優(yōu)化:采用分頁查詢/流式處理替代全量加載數(shù)據(jù),避免一次性將大量數(shù)據(jù)加載到內(nèi)存。
2. StackOverflowError —— 棧溢出
- 核心含義:JVM方法調(diào)用棧的深度超過最大值,無限遞歸是最典型、最常見的場景
- 典型場景:無限遞歸調(diào)用方法(
public void test() { test(); })、方法調(diào)用鏈過長(多層級業(yè)務(wù)方法嵌套) - 標(biāo)準(zhǔn)規(guī)避方式
- 代碼優(yōu)化:杜絕無限遞歸,檢查遞歸方法的終止條件,確保能正常退出;若遞歸層級過深,改為循環(huán)實(shí)現(xiàn)(根本解決方案);
- 調(diào)優(yōu)輔助:調(diào)整JVM棧大小參數(shù)(
-Xss,如-Xss1M),增大方法調(diào)用棧深度(謹(jǐn)慎使用,治標(biāo)不治本); - 代碼重構(gòu):將過長的方法調(diào)用鏈拆分為多個(gè)獨(dú)立方法,減少嵌套層級。
- 避坑點(diǎn):切勿依賴調(diào)整
-Xss解決問題,無限遞歸即使增大棧大小,最終仍會(huì)觸發(fā)棧溢出。
3. NoClassDefFoundError —— 類定義未找到
- 核心含義:編譯期能找到類,但運(yùn)行期JVM無法找到該類的字節(jié)碼文件(與
ClassNotFoundException的核心區(qū)別:前者是運(yùn)行期類加載失敗,后者是編譯/反射時(shí)類不存在) - 典型場景:編譯后刪除了類的class文件、依賴的第三方包編譯期存在但運(yùn)行期缺失、Maven/Gradle依賴包版本沖突
- 標(biāo)準(zhǔn)規(guī)避方式
- 環(huán)境檢查:確認(rèn)項(xiàng)目運(yùn)行時(shí)的classpath包含所有依賴包,編譯后的class文件完整無缺失;
- 依賴管理:使用Maven/Gradle統(tǒng)一管理依賴,執(zhí)行
clean install清理并重新編譯項(xiàng)目,避免依賴包缺失/沖突; - 類加載器排查:避免自定義類加載器的加載范圍沖突,確保類被JVM正確加載。
四、Java 常見異常速查表(含核心處理方式,快速查閱)
| 分類 | 異常名稱 | 核心關(guān)鍵詞 | 核心處理/規(guī)避方式 |
|---|---|---|---|
| 運(yùn)行時(shí)異常 | NullPointerException | 空對象、自動(dòng)拆箱 | Optional包裝/Objects非空校驗(yàn)/返回空對象而非null |
| ArrayIndexOutOfBoundsException | 數(shù)組索引越界 | 增強(qiáng)for循環(huán)/索引前置校驗(yàn)/以length為邊界 | |
| IndexOutOfBoundsException | 集合/字符串索引越界 | 非空校驗(yàn)/以size/length為邊界/Apache工具類輔助 | |
| ClassCastException | 強(qiáng)制類型轉(zhuǎn)換錯(cuò)誤 | instanceof判斷/Java14+模式匹配/集合指定泛型 | |
| InputMismatchException | Scanner輸入類型不匹配 | hasNextXxx()前置判斷/清空輸入緩沖區(qū)/先讀字符串再轉(zhuǎn)換 | |
| ArithmeticException | 整數(shù)除零、非法算術(shù)運(yùn)算 | 除數(shù)非零校驗(yàn)/try-catch兜底返回默認(rèn)值 | |
| IllegalArgumentException | 方法參數(shù)非法 | 方法入口校驗(yàn)/主動(dòng)拋出異常/Spring注解校驗(yàn) | |
| NumberFormatException | 字符串轉(zhuǎn)數(shù)值格式錯(cuò)誤 | NumberUtils工具類/正則校驗(yàn)/try-catch兜底 | |
| ConcurrentModificationException | 集合并發(fā)修改 | 迭代器修改/線程安全集合/遍歷后統(tǒng)一修改 | |
| UnsupportedOperationException | 不支持的操作 | 重新創(chuàng)建可修改集合/避免修改只讀集合 | |
| 受檢異常 | IOException(及子類) | 文件/流/網(wǎng)絡(luò)IO操作 | try-with-resources自動(dòng)關(guān)資源/finally釋放/日志+業(yè)務(wù)提示 |
| InterruptedException | 線程阻塞時(shí)被中斷 | 恢復(fù)中斷狀態(tài)/釋放資源/優(yōu)雅終止/切勿吞異常 | |
| SQLException | 數(shù)據(jù)庫JDBC操作 | 自動(dòng)關(guān)連接/事務(wù)回滾/詳細(xì)日志/通用業(yè)務(wù)提示 | |
| ClassNotFoundException | 反射/類加載找不到類 | 檢查類名拼寫/確認(rèn)依賴完整/排查classpath | |
| ParseException | 日期/字符串解析格式不匹配 | 統(tǒng)一格式/Java8+新日期API/前置格式校驗(yàn) | |
| JVM錯(cuò)誤 | OutOfMemoryError | 內(nèi)存溢出、OOM | 排查內(nèi)存泄漏/JVM堆調(diào)優(yōu)/分頁/流式處理/釋放無用引用 |
| StackOverflowError | 棧溢出、無限遞歸 | 杜絕無限遞歸/遞歸改循環(huán)/調(diào)整-Xss/拆分長調(diào)用鏈 | |
| NoClassDefFoundError | 運(yùn)行期找不到類定義 | 檢查classpath/重新編譯項(xiàng)目/Maven/Gradle統(tǒng)一依賴管理 |
五、Java 異常處理通用最佳實(shí)踐(所有場景均適用)
- 切勿空catch吞掉異常:尤其是
InterruptedException、IO異常、SQL異常,空catch會(huì)導(dǎo)致問題無法定位、資源泄漏、程序邏輯混亂; - 異常處理粒度適中:不要用一個(gè)try-catch捕獲所有異常(如
catch (Exception e)),按異常類型細(xì)分處理,便于精準(zhǔn)定位問題; - 資源釋放是核心:涉及IO、數(shù)據(jù)庫、網(wǎng)絡(luò)連接等資源的操作,必須保證資源釋放(優(yōu)先使用try-with-resources);
- 日志記錄要完整:捕獲異常時(shí)記錄異常堆棧+業(yè)務(wù)上下文(如參數(shù)、SQL語句),避免僅打印
e.printStackTrace(); - 前端/用戶提示要友好:隱藏底層異常細(xì)節(jié)(如數(shù)據(jù)庫地址、SQL語句),返回通用的業(yè)務(wù)提示(如“操作失敗,請稍后重試”);
- 運(yùn)行時(shí)異常以預(yù)防為主:通過判空、參數(shù)校驗(yàn)、索引檢查等邏輯從根源避免,而非依賴try-catch;
- 自定義異常語義清晰:復(fù)雜業(yè)務(wù)中自定義異常(繼承Exception/RuntimeException),讓異常更貼合業(yè)務(wù)場景(如
UserNotExistException),便于統(tǒng)一處理。 - 運(yùn)行時(shí)異常:重點(diǎn)在「預(yù)防」,通過嚴(yán)謹(jǐn)?shù)拇a邏輯(判空、參數(shù)校驗(yàn)、索引檢查、泛型使用)避免,是日常bug排查的主要對象;
- 受檢異常:重點(diǎn)在「處理」,編譯期強(qiáng)制捕獲/拋出,需根據(jù)業(yè)務(wù)場景做兜底(如IO異常關(guān)閉流、SQL異?;貪L事務(wù));
- Error:重點(diǎn)在「規(guī)避」,通過合理的JVM參數(shù)配置(如調(diào)整堆內(nèi)存)、優(yōu)化代碼(避免無限遞歸)防止,程序無法處理;
- 異常處理原則:切勿空catch吞掉異常(尤其是
InterruptedException),異常處理的核心是「恢復(fù)狀態(tài)、釋放資源、優(yōu)雅提示/終止」。
掌握以上異常的處理方式和通用原則,能大幅提升Java代碼的健壯性和可維護(hù)性,快速定位并解決開發(fā)中的各類異常問題,同時(shí)避免因異常處理不當(dāng)導(dǎo)致的資源泄漏、程序崩潰、數(shù)據(jù)不一致等嚴(yán)重問題。
總結(jié)
到此這篇關(guān)于Java常見異常全面梳理的文章就介紹到這了,更多相關(guān)Java常見異常內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決Unboxing of'stringRedisTemplate.hasKey(xx)'
文章介紹了在使用`stringRedisTemplate.hasKey(xx)`方法時(shí)可能會(huì)出現(xiàn)`NullPointerException`警告的原因,并提出了相應(yīng)的解決方法2026-03-03
JavaFX桌面應(yīng)用未響應(yīng)問題解決方案
這篇文章主要介紹了JavaFX桌面應(yīng)用未響應(yīng)問題解決方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07
詳解FileInputStream讀取文件數(shù)據(jù)的兩種方式
這篇文章主要介紹了詳解FileInputStream讀取文件數(shù)據(jù)的兩種方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08
Java線程池的優(yōu)點(diǎn)及池化技術(shù)的應(yīng)用
這篇文章主要介紹了Java線程池的優(yōu)點(diǎn)及池化技術(shù)的應(yīng)用,Java種提高程序的執(zhí)行效率有兩種實(shí)現(xiàn)方法,一個(gè)是使用線程、另一個(gè)是使用線程池,下文我們就來具體介紹該詳細(xì)內(nèi)容吧,需要的小伙伴可以參考一下2022-05-05
Java如何實(shí)現(xiàn)讀取txt文件內(nèi)容并生成Word文檔
本文主要介紹了通過Java實(shí)現(xiàn)讀取txt文件中的內(nèi)容,并將內(nèi)容生成Word文檔。文章的代碼非常詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以了解一下2021-12-12
java Quartz定時(shí)器任務(wù)與Spring task定時(shí)的幾種實(shí)現(xiàn)方法
本篇文章主要介紹了java Quartz定時(shí)器任務(wù)與Spring task定時(shí)的幾種實(shí)現(xiàn)方法的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-02-02

