JAVA:異常及異常處理
1.異常的概念
異常是指程式執行期間出現的錯誤,而非編譯時的語法錯誤。例如,程式要開啟不存在的資料夾、網路連線中斷、運算元越界、裝載一個不存在的類、算數異常等。
使用異常的目的在於通過使用少於目前數量的程式碼來簡化大型、可靠的程式的生成,並且通過這種方式可以使你更加自信:你的應用沒有未處理的錯誤。——《JAVA程式設計思想》如是說。
- 補充:
- 示例1:
public class TestException
{
public static void main(String[] args)
{
int array[] = {1, 2, 3};
System.out .println("array[5]=" + array[5]);
}
}
- 編譯,執行:
D:\JavaProject\demo14>javac TestException.java
D:\JavaProject\demo14>java TestException
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
at TestException.main(TestException.java:6)
出現了“陣列索引越界異常”,ArrayIndexOutOfBoundsException。在Java中,會嚴格檢查陣列的長度的,即在程式中,執行時不能出現數組越界的索引。
示例2:
public class TestException
{
public static void main(String[] args)
{
int a = 2/0;
}
}
- 編譯,執行:
D:\JavaProject\demo14>javac TestException.java
D:\JavaProject\demo14>java TestException
Exception in thread "main" java.lang.ArithmeticException: / by zero
at TestException.main (TestException.java:5)
出現了算數異常。執行打印出的異常資訊就是“錯誤的堆疊資訊”。
錯誤堆疊資訊:此錯誤可能是上一個錯誤導致的,上一個錯誤又可能是另外一個錯誤引起的,到底是由哪一個錯誤引起的,把這些錯誤資訊都打印出來,為程式設計師提供了除錯資訊,方便程式設計師進行錯誤追蹤和除錯。
2.異常的分類
3.捕獲異常及處理
3.0異常處理
- 補充:對於RuntimeException類的子類exception,我們可以也可以不使用try-catch語句來捕獲異常。對於除了RuntimeException類的子類exception之外的exception,我們都必須需要使用try-catch語句來捕獲異常,例如ArrayIndexOutOfBoundsException異常類。
- 對於異常,當前環境沒有足夠的資訊來解決這個問題,所以就把這個問題提交到一個更高級別的環境中,一直到main()方法,在這裡將作出正確的決定。
3.1 呼叫丟擲異常的方法使用try{}catch(){}語句
- try{}catch(){}語句:當try程式碼中的程式發生了異常,系統將這個異常發生的程式碼行號、類別資訊封裝到一個物件e中,並將這個物件傳遞給catch程式碼塊。
每個try語句必須有一個或多個catch語句,try程式碼塊與catch程式碼塊及finally程式碼塊之間不能有其他語句存在。
finally語句
(1)在try-catch語句後,還可以有一個finally語句,finally語句中的程式碼不管是異常是否被捕獲總是要執行的。
(2)finally中的程式碼塊不能被執行的唯一情況是:在被保護程式碼塊執行了System.exit(0);語句。
(3)finally語句的其他用法參見:《Java程式設計思想》第12.8節,或者我的下一篇博文:JAVA——finally塊中的程式碼什麼時候被執行、執行的效果是什麼?。- 示例3:
import java.io.*;
public class TestException
{
public static void main(String[] args)
{
FileInputStream fis = null;
fis = new FileInputStream("D:\\JavaProject\\demo14\\myfile.txt");/*myfile.txt裡面的內容是hello world!*/
int b = fis.read();
while(b != -1)
{
System.out.println((char)b);
b = fis.read();
}
fis.close();
}
}
- 編譯,執行:可以發現,存在異常沒有進行捕獲和處理(丟擲)。
D:\JavaProject\demo14>javac TestException.java
TestException.java:7: 錯誤: 未報告的異常錯誤FileNotFoundException; 必須對其進行
捕獲或宣告以便丟擲
fis = new FileInputStream("D:\\JavaProject\\demo14\\myfile.txt")
;
^
TestException.java:8: 錯誤: 未報告的異常錯誤IOException; 必須對其進行捕獲或宣告
以便丟擲
int b = fis.read();
^
TestException.java:12: 錯誤: 未報告的異常錯誤IOException; 必須對其進行捕獲或宣告
以便丟擲
b = fis.read();
^
TestException.java:14: 錯誤: 未報告的異常錯誤IOException; 必須對其進行捕獲或宣告
以便丟擲
fis.close();
^
4 個錯誤
- 檢視jdk文件:
(1)FileInputStream類有三個構造方法,此處呼叫的構造方法如下圖,可以看到該構造方法丟擲了一種沒找到目標檔案的異常類。因此,我們在呼叫該方法時,必須要使用try-catch語句進行捕獲異常。 - 若一個方法名後寫明瞭throws時,呼叫該方法時必須使用try-catch語句進行捕獲異常。當所丟擲的異常類是RuntimeException的子類時,可以不對其進行try-catch。
方法close()和方法read()都會丟擲異常:
示例4:
import java.io.*;
public class TestException
{
public static void main(String[] args)
{
FileInputStream fis = null;
try{
fis = new FileInputStream("D:\\JavaProject\\demo14\\myfile.txt");
int b = fis.read();
while(b != -1){
System.out.print((char)b);
b = fis.read();
}
}catch (FileNotFoundException fe){
fe.printStackTrace();
}catch (IOException ioe){
ioe.printStackTrace();
}finally{
try{
fis.close();
}catch (IOException ioe){
ioe.printStackTrace();
}
}
}
}
- 編譯,執行:輸出hello world!
D:\JavaProject\demo14>javac TestException.java
D:\JavaProject\demo14>java TestException
hello world!
3.2 宣告方法時丟擲異常:throws SomeException
- 如果將“示例4”的部分程式碼寫成一個方法:因為在這個func方法中,throws丟擲了兩個異常:FileNotFoundException 、 IOException。因此,我們在使用該方法時,就必須使用try-catch語句進行捕捉和處理。
- 在宣告時,所丟擲的異常是方法體中可能存在的所有異常類。而FileNotFoundException 是IOException的子類,所以在宣告方法時,直接丟擲IOException類異常即可。但是為了直觀,程式的可讀性,還是建議把所有可能的異常類均完整的寫出來。
而在使用該方法時,FileNotFoundException 是IOException的子類,可以直接建立父類的異常物件IOException即可。
示例5:
import java.io.*;
public class TestException
{
public static void main(String[] args) {
try{
TestException te = new TestException();
te.func();
}catch (IOException e){
e.printStackTrace();
}
}
void func() throws FileNotFoundException , IOException {
FileInputStream fis = new FileInputStream("D:\\JavaProject\\demo14\\myfile.txt");
int b = fis.read();
while(b != -1){
System.out.print((char)b);
b = fis.read();
}
fis.close();
}
}
- output:
D:\JavaProject\demo14>javac TestException.java
D:\JavaProject\demo14>java TestException
hello world!
- 當使用函式呼叫方法func()時,func丟擲的異常不是Runtime異常,而是必須捕捉的異常,因此在呼叫時必須寫try-catch,並進行處理。見示例6。
如果捕捉到這周異常後,也不知道怎麼處理,那麼繼續將這些異常給丟擲(在函式名後throws+要丟擲的異常),這時直接呼叫它即可,不需要try-catch語句。只是丟擲父類的異常IOException即可。見示例7。
示例6:
import java.io.*;
public class TestException
{
public static void main(String[] args) {
TestException te = new TestException();
te.f();
}
void func() throws FileNotFoundException , IOException {
FileInputStream fis = new FileInputStream("D:\\JavaProject\\demo14\\myfile.txt");
int b = fis.read();
while(b != -1){
System.out.print((char)b);
b = fis.read();
}
fis.close();
}
void f()
{
try{
func();
}catch (FileNotFoundException e){
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}
}
}
- 示例7:
import java.io.*;
public class TestException
{
public static void main(String[] args) {
try{
TestException te = new TestException();
te.f();
}catch (IOException e){
e.printStackTrace();
}
}
void func() throws FileNotFoundException , IOException {
FileInputStream fis = new FileInputStream("D:\\JavaProject\\demo14\\myfile.txt");
int b = fis.read();
while(b != -1){
System.out.print((char)b);
b = fis.read();
}
fis.close();
}
void f() throws IOException{
func();
}
}
3.3 手動的構造並丟擲異常物件
- 遇到異常時,遇到throws時,可自動的往外丟擲異常,我們不再去管它了。而還有一種異常,就必須自己手動的往外拋。
- 拋的格式:throw + 要丟擲的異常物件。方法定義時,指明要丟擲異常的類。
- 示例8:其中,可以指定異常資訊,如”被除數為0“,利用getMassage()方法就可獲得這個資訊。當丟擲new ArithmeticException(“被除數為0”);以後,這句後面的語句將不再執行。
void m(int i) throws ArithmeticException {
if(i==0)
throw new ArithmeticException("被除數為0");
}
4.使用自定義異常
-
- 注意:重寫方法需要丟擲與原方法所丟擲異常型別一致的異常,或那些異常的字跡,或不丟擲異常。