JAVA深化篇_2——異常機制
在具體談論java異常之前,我先簡單給大家介紹一下java異常機制的概念,以及異常機制的用途與使用環境。
首先我們先提一下異常概念:
異常(Exception)的概念
異常指程序運行過程中出現的非正常現象,例如除數為零、需要處理的文件不存在、數組下標越界等。
在Java的異常處理機制中,引進了很多用來描述和處理異常的類,稱為異常類。異常類定義中包含了該類異常的信息和對異常進行處理的方法。
其實呢,異常的本質就是:
異常機制本質
當程序出現異常,程序安全的退出、處理完后繼續執行的機制
我們開始看我們的第一個異常對象,并分析一下異常機制是如何工作的。
下面我們舉例分析一個具體的java異常
【示例】異常的分析
public class Test {
public static void main(String[] args) {
System.out.println("111");
int a = 1/0;
System.out.println("222");
}
}
執行結果如圖所示:
![]()

根據結果,我們可以看到執行“1/0”時發生了異常,程序終止了,沒有執行后面的打印“222”的動作。
如果我們使用try-catch來處理,程序遇到異常可以正常的處理,處理完成后,程序繼續往下執行:
public class Test {
public static void main(String[] args) {
System.out.println("111");
try {
int a = 1/0;
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("222");
}
}
執行結果如下:



程序在執行“1/0”仍然遇到異常,然后進行try-catch處理。處理完畢后,程序繼續往下執行,打印了“222”內容。
Java是采用面向對象的方式來處理異常的。處理過程:
-
拋出異常:在執行一個方法時,如果發生異常,則這個方法生成代表該異常的一個對象,停止當前執行路徑,并把異常對象提交給JRE。
-
捕獲異常:JRE得到該異常后,尋找相應的代碼來處理該異常。JRE在方法的調用棧中查找,從生成異常的方法開始回溯,直到找到相應的異常處理代碼為止。
異常分類:
Java中定義了很多異常類,這些類對應了各種各樣可能出現的異常事件,所有異常對象都是派生于Throwable類的一個實例。如果內置的異常類不能夠滿足需要,還可以創建自己的異常類。
Java對異常進行了分類,不同類型的異常分別用不同的Java類表示,所有異常的根類為java.lang.Throwable,Throwable下面又派生了兩個子類:Error和Exception。
1.Error(錯誤)
Error是程序無法處理的錯誤,表示運行應用程序中較嚴重問題。大多數錯誤與代碼編寫者執行的操作無關,而表示代碼運行時 JVM(Java 虛擬機)出現的問題。例如,Java虛擬機運行錯誤(Virtual MachineError),當 JVM 不再有繼續執行操作所需的內存資源時,將出現 OutOfMemoryError。這些異常發生時,Java虛擬機(JVM)一般會選擇線程終止。
Error表明系統JVM已經處于不可恢復的崩潰狀態中。
2.Exception(異常)
Exception是程序本身能夠處理的異常。
Exception類是所有異常類的父類,其子類對應了各種各樣可能出現的異常事件。 通常Java的異常可分為:
-
RuntimeException 運行時異常
-
CheckedException 已檢查異常
1.RuntimeException運行時異常
派生于RuntimeException的異常,如被 0 除、數組下標越界、空指針等,其產生比較頻繁,處理麻煩,如果顯式的聲明或捕獲將會對程序可讀性和運行效率影響很大。因此由系統自動檢測并將它們交給缺省的異常處理程序。
編譯器不處理RuntimeException, 程序員需要增加“邏輯處理來避免這些異常”。
ArithmeticException異常:試圖除以0
public class Test3 {
public static void main(String[ ] args) {
int b=0;
System.out.println(1/b);
}
}
執行結果如圖所示:

解決如上異常需要修改代碼:
public class Test3 {
public static void main(String[ ] args) {
int b=0;
if(b!=0){
System.out.println(1/b);
}
}
}
?NullPointerException異常
public class Test4 {
public static void main(String[ ] args) {
String str=null;
System.out.println(str.charAt(0));
}
}
?執行結果如圖所示:

解決如上異常需要修改代碼:
public class Test3 {
public static void main(String[ ] args) {
int b=0;
if(b!=0){
System.out.println(1/b);
}
}
}
?
ClassCastException異常
class Animal{
}
class Dog extends Animal{
}
class Cat extends Animal{
}
public class Test5 {
public static void main(String[ ] args) {
Animal a=new Dog();
Cat c=(Cat)a;
}
}
執行結果如圖所示:

解決ClassCastException的典型方式:
public class Test5 {
public static void main(String[ ] args) {
Animal a = new Dog();
if (a instanceof Cat) {
Cat c = (Cat) a;
}
}
}
?ArrayIndexOutOfBoundsException異常(數組索引越界異常)
public class Test6 {
public static void main(String[ ] args) {
int[ ] arr = new int[5];
System.out.println(arr[5]);
}
}
?執行結果如圖所示:

解決數組索引越界異常的方式,增加關于邊界的判斷:
public class Test6 {
public static void main(String[ ] args) {
int[ ] arr = new int[5];
int a = 5;
if (a < arr.length) {
System.out.println(arr[a]);
}
}
}
?NumberFormatException異常(數字格式化異常)
public class Test7 {
public static void main(String[ ] args) {
String str = "1234abcf";
System.out.println(Integer.parseInt(str));
}
}
執行結果如圖所示:

數字格式化異常的解決,可以引入正則表達式判斷是否為數字:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
?
?
public class Test7 {
public static void main(String[ ] args) {
String str = "1234abcf";
Pattern p = Pattern.compile("^\\d+$");
Matcher m = p.matcher(str);
if (m.matches()) { // 如果str匹配代表數字的正則表達式,才會轉換
System.out.println(Integer.parseInt(str));
}
}
}
2.CheckedException已檢查異常
異常在編譯時就必須處理,否則無法通過編譯。
CheckedException異常的處理方式有兩種:
-
使用
try/catch捕獲異常 -
使用
throws聲明異常。
異常的處理方式之一:捕獲異常
try:
try語句指定了一段代碼,該段代碼就是異常捕獲并處理的范圍。在執行過程中,當任意一條語句產生異常時,就會跳過該條語句中后面的代碼。代碼中可能會產生并拋出一種或幾種類型的異常對象,它后面的catch語句要分別對這些異常做相應的處理。
一個try語句必須帶有至少一個catch語句塊或一個finally語句塊。
注意事項
當異常處理的代碼執行結束以后,不會回到
try語句去執行尚未執行的代碼。
catch:
-
每個
try語句塊可以伴隨一個或多個catch語句,用于處理可能產生的不同類型的異常對象。 -
catch捕獲異常時的捕獲順序:如果異常類之間有繼承關系,先捕獲子類異常再捕獲父類異常。
finally:
-
不管是否發生了異常,都必須要執行。
-
通常在
finally中關閉已打開的資源,比如:關閉文件流、釋放數據庫連接等。
try-catch-finally語句塊的執行過程詳細分析:
-
程序首先執行可能發生異常的
try語句塊。 -
如果
try語句沒有出現異常則執行完后跳至finally語句塊執行; -
如果
try語句出現異常,則中斷執行并根據發生的異常類型跳至相應的catch語句塊執行處理。 -
catch語句塊可以有多個,分別捕獲不同類型的異常。 -
catch語句塊執行完后程序會繼續執行finally語句塊。 -
finally語句是可選的,如果有的話,則不管是否發生異常,finally語句都會被執行。
【示例】異常處理的典型代碼(捕獲異常)
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class Test8 {
public static void main(String[ ] args) {
FileReader reader = null;
try {
reader = new FileReader("d:/a.txt");
char c = (char) reader.read();
char c2 = (char) reader.read();
System.out.println("" + c + c2);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (reader != null) {
reader.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
常用開發環境中,自動增加try-catch代碼塊的快捷鍵:
將需要處理異常的代碼選中。
IDEA中,使用:ctrl+alt+t
eclipse中,使用:ctrl+shift+z
異常的處理方式之二:聲明異常(throws子句)
1. CheckedException產生時,不一定立刻處理它,可以把異常throws,由調用者處理。
2. 一個方法拋出多個已檢查異常,就必須在方法的首部列出所有的異常。
【示例】異常處理的典型代碼(聲明異常拋出throws)
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class Test9 {
public static void main(String[ ] args) {
try {
readFile("joke.txt");
} catch (FileNotFoundException e) {
System.out.println("所需文件不存在!");
} catch (IOException e) {
System.out.println("文件讀寫錯誤!");
}
}
public static void readFile(String fileName) throws FileNotFoundException,
IOException {
FileReader in = new FileReader(fileName);
int tem = 0;
try {
tem = in.read();
while (tem != -1) {
System.out.print((char) tem);
tem = in.read();
}
} finally {
if(in!=null) {
in.close();
}
}
}
}
注意事項
??方法重寫中聲明異常原則:子類重寫父類方法時,如果父類方法有聲明異常,那么子類聲明的異常范圍不能超過父類聲明的范圍。
JDK新特性_
try-with-resource自動關閉AutoClosable接口的資源
JAVA中,JVM的垃圾回收機制可以對內部資源實現自動回收,給開發者帶來了極大的便利。
但是JVM對外部資源(調用了底層操作系統的資源)的引用卻無法自動回收,例如數據庫連接,網絡連接以及輸入輸出IO流等。這些連接就需要我們手動去關閉,不然會導致外部資源泄露,連接池溢出以及文件被異常占用等。
JDK7之后,新增了“try-with-resource”。它可以自動關閉實現了AutoClosable接口的類,實現類需要實現close()方法。
”try-with-resources “ 將try-catch-finally 簡化為try-catch,這其實是一種語法糖,在編譯時仍然會進行轉化為try-catch-finally 語句。
import java.io.FileReader;
public class Test8 {
public static void main(String[ ] args) {
try(FileReader reader = new FileReader("d:/a.txt");) {
char c = (char) reader.read();
char c2 = (char) reader.read();
System.out.println("" + c + c2);
} catch (Exception e) {
e.printStackTrace();
}
}
}
浙公網安備 33010602011771號