異常(或異常事件)是在執行程式期間出現的問題。 當發生異常時,程式的正常流程被中斷並且程式/應用程式異常終止,這是對於使用者來說是非常不友好的。因此,要合理地處理這些異常。
發生異常有許多不同的原因,以下是發生異常的一些情況。
有一些異常是由使用者錯誤引起的,也有一些異常是由程式員錯誤引起的,或者是由以某種物理資源引起的。
基於這三類異常,您需要了解它們以了解在Java中例外處理工作原理。
FileReader
類從檔案中讀取資料,如果其建構函式中指定的檔案不存在,則會發生FileNotFoundException
異常,並且編譯器會提示程式員處理異常。範例程式碼 -import java.io.File;
import java.io.FileReader;
public class FilenotFound_Demo {
public static void main(String args[]) {
File file = new File("E://file.txt");
FileReader fr = new FileReader(file);
}
}
如果編譯上述程式,則會出現以下異常。
C:\>javac FilenotFound_Demo.java
FilenotFound_Demo.java:8: error: unreported exception FileNotFoundException; must be caught or declared to be thrown
FileReader fr = new FileReader(file);
^
1 error
註 - 由於
FileReader
類的read()
和close()
方法丟擲IOException
,可以看到到編譯器通知要求處理IOException
以及FileNotFoundException
這兩個異常。
未檢查異常 - 未檢查的異常是在執行時發生的異常。這些也稱為執行時異常。 這些包括程式設計錯誤,例如邏輯錯誤或API的不當使用,編譯時忽略執行時異常。
例如,如果在程式中宣告了一個大小為5
的陣列,但是卻要存取陣列的第6
個元素,則會發生ArrayIndexOutOfBoundsExceptionexception
異常。
public class Unchecked_Demo {
public static void main(String args[]) {
int num[] = {1, 2, 3, 4};
System.out.println(num[5]);// 存取第6個元素
}
}
如果編譯並執行上述程式,則會出現以下異常。
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
at Exceptions.Unchecked_Demo.main(Unchecked_Demo.java:8)
錯誤 - 這個嚴格來說不是異常,它是超出使用者或程式員控制的問題。 程式碼中通常會忽略錯誤,因為很少對錯誤做任何事情。 例如,如果發生堆疊溢位,則會出現錯誤。 它們在編譯時也被忽略。
所有異常類都是java.lang.Exception
類的子型別。 Exception
類是Throwable
類的子類。 除了Exception
類之外,還有另一個名稱為Error
的子類,它派生自Throwable
類。
錯誤是在嚴重故障的情況下發生的異常情況,Java程式不處理這些情況。 生成錯誤以指示執行時環境生成的錯誤。例如:JVM記憶體不足。 通常,程式無法從錯誤中恢復。
Exception
類有兩個主要的子類:IOException
類和RuntimeException
類。
以下是最常見的已檢查和未檢查的Java內建異常類列表。
以下是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
關鍵字的組合捕獲異常。try/catch
塊放在可能生成異常的程式碼周圍。try/catch
塊中的程式碼稱為受保護程式碼,使用try/catch
的語法如下所示 -
語法
try {
// Protected code
} catch (ExceptionName e1) {
// Catch block
}
將容易出現異常的程式碼放在try
塊中。 發生異常時,異常由與其關聯的catch
塊處理。 每個try
塊都應該緊跟一個catch
塊或者一個塊finally
。
catch
語句涉及宣告嘗試捕獲的異常型別。 如果受保護程式碼中發生異常,則會檢查try
之後的catch
塊(或多個塊)。如果發生的異常型別列在catch
塊中,則異常將傳遞給catch
塊,就像將引數傳遞給方法引數一樣。
範例
以下是使用2
個元素宣告的陣列,然後嘗試存取引發異常的陣列的第3
個元素。
// 檔案 : ExcepTest.java
import java.io.*;
public class ExcepTest {
public static void main(String args[]) {
try {
int a[] = new int[2];
System.out.println("Access element three :" + a[3]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Exception thrown :" + e);
}
System.out.println("Out of the block");
}
}
執行上面範例程式碼,得到以下結果:
Exception thrown :java.lang.ArrayIndexOutOfBoundsException: 3
Out of the block
try
塊後面可以跟多個catch
塊,多個catch
塊的語法如下所示 -
語法
try {
// Protected code
} catch (ExceptionType1 e1) {
// Catch block
} catch (ExceptionType2 e2) {
// Catch block
} catch (ExceptionType3 e3) {
// Catch block
}
上面的語句中放置了三個catch
塊,但只需一次嘗試即可獲得任意數量的塊。 如果受保護程式碼中發生異常,則會將異常丟擲到列表中的第一個catch
塊。 如果丟擲的異常的資料型別與ExceptionType1
匹配,則會在那裡捕獲它。 如果不是,則異常傳遞給第二個catch
語句。 這種情況一直持續到異常被捕獲,在這種情況下,當前方法停止執行,異常將被拋到呼叫堆疊上的前一個方法。
以下是顯示如何使用多個try/catch
語句的程式碼段。
try {
file = new FileInputStream(fileName);
x = (byte) file.read();
} catch (IOException i) {
i.printStackTrace();
return -1;
} catch (FileNotFoundException f) // Not valid! {
f.printStackTrace();
return -1;
}
捕獲多種型別的例外
從Java 7開始,可以使用單個catch
塊處理多個異常,此功能簡化了程式碼。 下面是應用範例 -
catch (IOException|FileNotFoundException ex) {
logger.log(ex);
throw ex;
如果方法不處理已檢查的異常,則該方法必須使用throws
關鍵字宣告它。 throws
關鍵字應放置在方法簽名的末尾。
可以使用throw
關鍵字丟擲異常,可以是新範例化的異常,也可以是剛捕獲的異常。
throws
和throw
關鍵字之間的區別是,throws
用於推遲對已檢查異常的處理,throw
用於顯式呼叫異常。
以下方法宣告它丟擲RemoteException
-
import java.io.*;
public class className {
public void deposit(double amount) throws RemoteException {
// Method implementation
throw new RemoteException();
}
// Remainder of class definition
}
可以將方法宣告為丟擲多個異常,在這種情況下,異常在以逗號分隔的列表中宣告。 例如,以下方法宣告它丟擲RemoteException
和InsufficientFundsException
異常 -
import java.io.*;
public class className {
public void withdraw(double amount) throws RemoteException,
InsufficientFundsException {
// Method implementation
}
// Remainder of class definition
}
finally
塊在try
塊或catch
塊之後。無論受保護的程式碼塊是否發生異常,最終都會執行finally
塊中的程式碼。
使用finally
塊執行要執行的任何清理型別語句,無論受保護程式碼中發生什麼。
finally
塊放置在catch
塊的末尾,它的語法語法如下 -
try {
// Protected code
} catch (ExceptionType1 e1) {
// Catch block
} catch (ExceptionType2 e2) {
// Catch block
} catch (ExceptionType3 e3) {
// Catch block
}finally {
// The finally block always executes.
}
範例
public class ExcepTest {
public static void main(String args[]) {
int a[] = new int[2];
try {
System.out.println("Access element three :" + a[3]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Exception thrown :" + e);
}finally {
a[0] = 6;
System.out.println("First element value: " + a[0]);
System.out.println("The finally statement is executed");
}
}
}
執行上面範例程式碼,得到以下結果 -
Exception thrown :java.lang.ArrayIndexOutOfBoundsException: 3
First element value: 6
The finally statement is executed
使用finally
時,需要注意以下規則 -
try
語句就不能存在catch
子句。try/catch
塊,finally
子句就不是必須的。catch
子句或finally
子句,則try
塊不能出現。try
,catch
,finally
塊之間不能出現任何程式碼。通常,當使用流,連線等任何資源時,要使用finally
塊顯式關閉它們。 在下面的程式中使用FileReader
從檔案中讀取資料,然後使用finally
塊關閉它。
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class ReadData_Demo {
public static void main(String args[]) {
FileReader fr = null;
try {
File file = new File("file.txt");
fr = new FileReader(file); char [] a = new char[50];
fr.read(a); // reads the content to the array
for(char c : a)
System.out.print(c); // prints the characters one by one
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fr.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
try-with-resources
,也稱為自動資源管理,是Java 7中引入的一種新的例外處理機制,它自動關閉try/catch
塊中使用的資源。
要使用此語句,只需在括號內宣告所需的資源,建立的資源將在塊結束時自動關閉。 以下是try-with-resources
語句的語法。
語法
try(FileReader fr = new FileReader("file path")) {
// use the resource
} catch () {
// body of catch
}
}
以下是使用try-with-resources
語句讀取檔案中資料的程式。
import java.io.FileReader;
import java.io.IOException;
public class Try_withDemo {
public static void main(String args[]) {
try(FileReader fr = new FileReader("E://file.txt")) {
char [] a = new char[50];
fr.read(a); // reads the contentto the array
for(char c : a)
System.out.print(c); // prints the characters one by one
} catch (IOException e) {
e.printStackTrace();
}
}
}
在使用try-with-resources
語句時,請牢記以下幾點。
try-with-resources
語句的類,它應該實現AutoCloseable
介面,並且它的close()
方法在執行時自動呼叫。try-with-resources
語句中宣告多個類。try-with-resources
語句的try
塊中宣告多個類時,這些類將以相反的順序關閉。try
塊的普通try/catch
塊相同。try
中宣告的資源在try-block
開始之前範例化。try
塊宣告的資源被隱式宣告為final
。可以在Java中建立自己的異常。 在編寫自己的異常類時,請注意以下幾點 -
Throwable
的子類。Exception
類。RuntimeException
類。可以定義自己的Exception
類,如下所示 -
class MyException extends Exception {
}
只需要擴充套件預定義的Exception
類來建立自己的Exception
類。 這些都是經過檢查的異常。 以下InsufficientFundsException
類是一個使用者定義的異常,它擴充套件了Exception
類,使其成為一個已檢查的異常。異常類與任何其他類一樣,包含有用的欄位和方法。
範例
// 檔案:InsufficientFundsException.java
import java.io.*;
public class InsufficientFundsException extends Exception {
private double amount;
public InsufficientFundsException(double amount) {
this.amount = amount;
}
public double getAmount() {
return amount;
}
}
為了演示如何使用使用者定義的異常,以下CheckingAccount
類的withdraw()
方法中包含丟擲InsufficientFundsException
。
// 檔案名稱:CheckingAccount.java
import java.io.*;
public class CheckingAccount {
private double balance;
private int number;
public CheckingAccount(int number) {
this.number = number;
}
public void deposit(double amount) {
balance += amount;
}
public void withdraw(double amount) throws InsufficientFundsException {
if(amount <= balance) {
balance -= amount;
}else {
double needs = amount - balance;
throw new InsufficientFundsException(needs);
}
}
public double getBalance() {
return balance;
}
public int getNumber() {
return number;
}
}
以下BankDemo
程式演示了如何呼叫CheckingAccount
類的deposit()
和withdraw()
方法。
// 檔案: BankDemo.java
public class BankDemo {
public static void main(String [] args) {
CheckingAccount c = new CheckingAccount(101);
System.out.println("Depositing $500...");
c.deposit(500.00);
try {
System.out.println("\nWithdrawing $100...");
c.withdraw(100.00);
System.out.println("\nWithdrawing $600...");
c.withdraw(600.00);
} catch (InsufficientFundsException e) {
System.out.println("Sorry, but you are short $" + e.getAmount());
e.printStackTrace();
}
}
}
執行上面範例程式碼,得到以下結果 -
Depositing $500...
Withdrawing $100...
Withdrawing $600...
Sorry, but you are short $200.0
InsufficientFundsException
at CheckingAccount.withdraw(CheckingAccount.java:25)
at BankDemo.main(BankDemo.java:13)
常見異常
在Java中,可以定義兩個分類:異常和錯誤。
NullPointerException
,ArrayIndexOutOfBoundsException
,ClassCastException
。IllegalArgumentException
,IllegalStateException
。