前言
程序在運行過程中發生錯誤或異常情況是不可避免的,如果每一個運行時錯誤都由程序員手動控制和處理,其工作量是不可想象的。
Java語言中的異常處理機制就解決的上述問題,把錯誤與異常的管理帶到了面向對象的世界
什麼是異常?
異常是程序中的一些錯誤,但並不是所有的錯誤都是異常,並且錯誤有時候是可以避免的。 程序運行過程中,出現不期而至的各種狀況,將它們統稱爲異常。
比如說,你的代碼少了一個分號,那麼運行出來結果是提示是錯誤 java.lang.Error;
如果你用System.out.println(11/0),那麼你是因爲你用0做了除數,會拋出 java.lang.ArithmeticException 的異常。
異常發生的原因有很多,通常包含以下幾大類:
-
用戶輸入了非法數據。
-
要打開的文件不存在/文件格式不對。
-
讀取空數據庫
-
網絡通信時連接中斷
-
JVM內存溢出。
這些異常有的是因爲用戶錯誤引起,有的是程序錯誤引起的,還有其它一些是因爲物理錯誤引起的。-
簡單分類
檢查性異常
最具代表的檢查性異常是用戶錯誤或問題引起的異常,這是程序員無法預見的。
例如要打開一個不存在文件時,一個異常就發生了,這些異常在編譯時不能被簡單地忽略。
運行時異常
運行時異常是可能被程序員避免的異常。
與檢查性異常相反,運行時異常可以在編譯時被忽略。
錯誤ERROR
錯誤不是異常,而是脫離程序員控制的問題。錯誤在代碼中通常被忽略。
例如,當棧溢出時,一個錯誤就發生了,它們在編譯也檢查不到的。
異常的體系結構
Java把異常當做對象來處理,並定義了一個基類java.lang.Throwable作爲所有異常的超類
Java 語言定義了許多異常類在 java.lang 標準包中,主要分爲Error和Exception兩大類。
Error
Error類對象由JVM生成並拋出,大多數錯誤與代碼編寫者所執行的操作無關。
錯誤 | 描述 |
---|---|
VirtualMachineError | 拋出以表明Java虛擬機已損壞或已耗盡資源以使其繼續運行。 |
OutOfMemoryError | Java虛擬機由於內存不足而無法分配對象時拋出,並且垃圾收集器不再有可用的內存。 |
StackOverflowError | 當堆棧溢出發生時拋出一個應用程序遞歸太深。 |
InternalError | 在Java虛擬機中引發了一些意外的內部錯誤。 |
UnknownError | 當Java虛擬機中出現未知但嚴重的異常時拋出。 |
AWTError | 當出現嚴重的抽象窗口工具包錯誤時拋出。 |
還有發生在虛擬機試圖執行應用時,如類定義錯誤NoClassDefFoundError、鏈接錯誤LinkageError
這些錯誤時不可查的,因爲他們在應用程序的控制和處理能力之外,而且絕大多數是程序運行時不允許出現的狀況。
Exception
在Exception分支中有一個重要的子類RuntimeException(運行時異常)
異常 | 描述 |
---|---|
ArrayIndexOutOfBoundsException | 用非法索引訪問數組時拋出的異常。如果索引爲負或大於等於數組大小,則該索引爲非法索引。 |
NullPointerException | 空指針異常 |
ClassCastException | 當試圖將對象強制轉換爲不是實例的子類時,拋出該異常。 |
ArithmeticException | 當出現異常的運算條件時,拋出此異常。例如,一個整數"除以0"時,拋出此類的一個實例。 |
IllegalMonitorStateException | 拋出的異常表明某一線程已經試圖等待對象的監視器,或者試圖通知其他正在等待對象的監視器而本身沒有指定監視器的線程。 |
ClassNotFoundException | 找不到類 |
IllegalThreadStateException | 線程沒有處於請求操作所要求的適當狀態時拋出的異常。 |
IndexOutOfBoundsException | 指示某排序索引(例如對數組、字符串或向量的排序)超出範圍時拋出。 |
NegativeArraySizeException | 如果應用程序試圖創建大小爲負的數組,則拋出該異常。 |
NullPointerException | 當應用程序試圖在需要對象的地方使用 null 時,拋出該異常 |
NumberFormatException | 當應用程序試圖將字符串轉換成一種數值類型,但該字符串不能轉換爲適當格式時,拋出該異常。 |
SecurityException | 由安全管理器拋出的異常,指示存在安全侵犯。 |
StringIndexOutOfBoundsException | 此異常由 String 方法拋出,指示索引或者爲負,或者超出字符串的大小。 |
UnsupportedOperationException | 當不支持請求的操作時,拋出該異常。 |
非檢查異常,可以在程序中捕獲處理,也可以不處理。
這些異常一般是由程序邏輯錯誤引起的,程序應該從邏輯角度儘可能避免這類異常的發生。
Error和Exception的區別
Error通常是災難性的致命錯誤,是程序無法控制和處理的,當出現這些異常時,JVM一般會選擇終止線程;
Exception通常情況下是可以被程序處理的,並且在程序中應該儘可能的去處理這些異常。
異常方法
下面的列表是 Throwable 類的主要方法:
序號 | 方法及說明 |
---|---|
1 | public String getMessage() 返回關於發生的異常的詳細信息。這個消息在Throwable 類的構造函數中初始化了。 |
2 | public Throwable getCause() 返回一個Throwable 對象代表異常原因。 |
3 | public String toString() 使用getMessage()的結果返回類的串級名字。 |
4 | public void printStackTrace() 打印toString()結果和棧層次到System.err,即錯誤輸出流。 |
5 | public StackTraceElement [] getStackTrace() 返回一個包含堆棧層次的數組。下標爲0的元素代表棧頂,最後一個元素代表方法調用堆棧的棧底。 |
6 | public Throwable fillInStackTrace() 用當前的調用棧層次填充Throwable 對象棧層次,添加到棧層次任何先前信息中。 |
異常處理機制
五個關鍵字try、catch、finally、throw、throws
捕獲異常try /catch
使用 try 和 catch 關鍵字可以捕獲異常。try/catch 代碼塊放在異常可能發生的地方。
try/catch代碼塊中的代碼稱爲保護代碼,使用 try/catch 的語法如下:
try
{
// try監控區域
}catch(ExceptionName e)
{
// catch 捕獲異常
}catch(ExceptionName e1)
{
// catch 捕獲異常
}finally{
// 處理善後工作
}
finally區可以不要,在IO流,資源關閉時使用。
catch(想要捕獲的異常類型) 最高級別Throwable
假設要捕獲多個異常:從小到大!
IDEA快捷鍵
選中監控區域代碼 --> Ctrl + Alt + T
拋出異常throws/throw
如果一個方法沒有捕獲到一個檢查性異常,那麼該方法必須使用 throws 關鍵字來聲明。throws 關鍵字放在方法簽名的尾部。
也可以使用 throw 關鍵字拋出一個異常,無論它是新實例化的還是剛捕獲到的。
throws是用在方法名尾部,可以聲明拋出多個異常,多個異常之間用逗號隔開。
import java.io.*;
public class className
{
public void withdraw(double amount) throws RemoteException,
InsufficientFundsException
{
// Method implementation
}
//Remainder of class definition
}
throw是用在方法體內,主動拋出異常
public class ThrowTest {
public static void main(String[] args) {
int a = 1;
int b = 0;
try {
System.out.println(divide(a, b));
} catch (Exception e) {
System.out.println("分母不能爲0");
//e.printStackTrace();
}
}
public static double divide(int a, int b) {
if (b == 0) {
// 主動拋出異常
throw new ArithmeticException();
}
return 1.0*a/b;
}
}
結果
分母不能爲0
自定義異常
使用Java內置異常類可以描述在編程時出現的大部分異常情況。除此之外,用戶還可以自定義異常。
用戶自定義異常類,只需繼承Exception類即可。
自定義異常步驟:
-
創建自定義異常類
-
在方法中通過throw關鍵字拋出異常對象
-
如果在當前拋出異常的方法中處理異常,可以使用try-catch語句捕獲並處理;
否則在方法聲明出通過throws關鍵字向外拋出異常
-
在出現異常方法的調用者中捕獲並處理異常
自定義異常類
public class CustomException extends Exception {
// 傳遞數字
private int detail;
public CustomException(int detail) {
this.detail = detail;
}
// 打印異常信息
@Override
public String toString() {
return "CustomException{" + detail + '}';
}
}
測試方法test拋出異常 throw,再通過throws向外拋出
public class Test {
public static void main(String[] args) {
try {
test(11);
} catch (CustomException e) {
System.out.println("打印自定義異常信息");
System.out.println(e);
}
}
static void test(int a) throws CustomException {
System.out.println("傳輸一個參數" + a);
if (a > 10) {
// 拋出自定義異常
throw new CustomException(a);
}
System.out.println("ok");
}
}
最後在main方法捕獲處理異常
總結
- 處理運行是異常時,採用邏輯去合理規避,同時輔助try-catch處理
- 在多重catch塊後面,可以加一個catch(Exception)來處理可能會被遺漏的異常
- 對於不確定的代碼,也可以加上try-catch,處理潛在的異常
- 儘量去處理異常,切忌只是簡單的調用printStackTrace()去打印輸出
- 具體如何處理異常,要根據不同的業務需求和異常類型去決定
- 儘量添加finally語句塊去釋放佔用的資源。