Java中的異常和處理
Java異常
目錄
- 異常概述
- 異常處理
- 丟擲異常
什麼是異常:
那麼究竟什麼是異常?當面對異常時,該如何有效處理呢?
異常就是程式在執行中所發生的不正常事件,如所需檔案找不到、網路連線不通或中斷、算術運算出錯(如被除零數)、陣列下標越界、裝載了一個不存在的類、對null物件操作、型別轉換異常等。異常會中斷執行中的程式。
異常處理:
什麼是異常處理?異常處理機制就像我們對平時可能會遇到的意外情況、預先想好的一些處理方法、也就是說在程式執行程式碼的時候,萬一發生了異常,程式會按照預定的處理方法對異常進行處理。異常處理完成後程式繼續執行。
java異常是通過五個關鍵字來處理的:try、catch、finally、thorw和thorws下面將依次講解。
try-catch塊
採用java的異常處理機制進行處理,把可能發生異常的程式碼放入try語句塊中,並使用catch語句塊捕獲異常,下面使用簡單的示例程式碼:
import java.util.Scanner; /** * 使用try-catch進行異常處理 */ public class testException { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("請輸入被除數"); /*把容易出錯的程式碼發入try中*/ try { int num = scanner.nextInt(); System.out.println("請輸入除數"); int num2 = scanner.nextInt(); System.out.println(String.format("%d/%d=%d",num,num2,num/num2)); /*用catch來捕捉異常*/ }catch (Exception e){ System.out.println("出現錯誤,被除數和除數必須是整數或被除數不能為零"); e.printStackTrace(); } } }
try-catch程式塊執行流程比較簡單,首先是執行try語句塊中的程式碼,這時可能會有三種情況;
一:如果try語句塊中所有語句正常執行完畢,不會發生異常,那麼catch塊中的所有語句將會全部被忽略,我們輸入正確的如下:
二:如果try語句塊在執行過程中遇到異常,並且這個異常在catch中宣告的異常型別匹配,那麼在tey塊中其餘的程式碼將被忽略,而相應的catch塊將會被執行、匹配是指catch所處理的異常型別與所生成的異常型別完全一致或是它的父類。
錯誤的:
三:如果try語句塊在執行過程中遇到異常,並且這個異常在catch中沒有被宣告,那麼程式將會立刻退出。
列出一些常見的異常及其用途;
異常 | 說明 |
---|---|
Exception | 異常層次結構的根類 |
ArithmeticException | 當出現異常的運算條件時,丟擲此異常。例如,一個整數"除以零"時,丟擲此類的一個例項 |
ArrayIndexOutOfBoundsException | 用非法索引訪問陣列時丟擲的異常。如果索引為負或大於等於陣列大小,則該索引為非法索引 |
ArrayStoreException | 試圖將錯誤型別的物件儲存到一個物件陣列時丟擲的異常 |
ClassCastException | 當試圖將物件強制轉換為不是例項的子類時,丟擲該異常。 |
illegalArgumentException | 丟擲的異常表明向方法傳遞了一個不合法或不正確的引數。 |
illegalMonitorStateException | 丟擲的異常表明某一執行緒已經試圖等待物件的監視器,或者試圖通知其他正在等待物件的監視器而本身沒有指定監視器的執行緒。 |
illegalStateException | 在非法或不適當的時間呼叫方法時產生的訊號。換句話說,即 Java 環境或 Java 應用程式沒有處於請求操作所要求的適當狀態下。 |
illegalThreadStateException | 執行緒沒有處於請求操作所要求的適當狀態時丟擲的異常。 |
IndexOutOfBoundsException | 指示某排序索引(例如對陣列、字串或向量的排序)超出範圍時丟擲。 |
NegativeArraySizeException | 如果應用程式試圖建立大小為負的陣列,則丟擲該異常。 |
NullPointerException | 當應用程式試圖在需要物件的地方使用 null 時,丟擲該異常 |
NumberFormatException | 當應用程式試圖將字串轉換成一種數值型別,但該字串不能轉換為適當格式時,丟擲該異常。 |
SecurityException | 由安全管理器丟擲的異常,指示存在安全侵犯。 |
StringIndexOutOfBoundsException | 此異常由 String 方法丟擲,指示索引或者為負,或者超出字串的大小。 |
UnsupportedOperationException | 當不支援請求的操作時,丟擲該異常。下面的表中列出了 Java 定義在 java.lang 包中的檢查性異常類。 |
ClassNotFoundException | 應用程式試圖載入類時,找不到相應的類,丟擲該異常。 |
CloneNotSupportedException | 當呼叫 Object 類中的 clone 方法克隆物件,但該物件的類無法實現 Cloneable 介面時,丟擲該異常 |
IllegalAccessException | 拒絕訪問一個類的時候,丟擲該異常。 |
InstantiationException | 試圖使用 Class 類中的 newInstance 方法建立一個類的例項,而指定的類物件因為是一個介面或是一個抽象類而無法例項化時,丟擲該異常。 |
InterruptedException | 一個執行緒被另一個執行緒中斷,丟擲該異常 |
NoSuchFieldException | 請求的變數不存在 |
NoSuchMethodException | 請求的方法不存在 |
try-catch-finally塊
在try-catch程式碼後面加上finally裡面放入一些語句,無論發生什麼異常,finally中的程式碼總被執行,如下:
import java.util.Scanner;
/**
* 使用try-catch-finally進行異常處理
*/
public class testException {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("請輸入被除數");
/*把容易出錯的程式碼發入try中*/
try {
int num = scanner.nextInt();
System.out.println("請輸入除數");
int num2 = scanner.nextInt();
System.out.println(String.format("%d/%d=%d",num,num2,num/num2));
/*用catch來捕捉異常*/
}catch (Exception e){
System.out.println("出現錯誤,被除數和除數必須是整數或被除數不能為零");
System.out.println(e.getMessage());
}finally {
System.out.println("感謝使用哦");
}
}
}
try-catch-finally程式塊執行流程大概分為兩種情況:
一:如果try語句中的所有程式碼正常執行完畢,那麼finally塊就會被執行。catch塊不會被執行。
二:如果tey塊中程式碼出現異常,就會執行catch塊中的程式碼,不管catch有沒有匹配型別finally塊中的程式碼都會被執行
finally唯一不被執行情況是,在異常處理catch程式碼中執行System.exit(1),將退出java虛擬機器。
多重catch塊
一段程式碼可能會引發多種型別異常,這時,可以在一個try語句後面跟多個catch語句塊,分別處理不同的異常。但排列順序必須是從子類到父類,最後一個一般都是Exception類,因為所有異常子類都繼承Exception類,所以如果將異常父類放在前面,那麼所有的異常都將被捕獲,後面的catch中的子類將得不到執行的機會。
但執行時,系統從上倒下對每個catch塊語句處理的異常型別進行檢測,並執行第一個與異常型別匹配的catch塊,其他的catch塊全部會被忽略。
import java.util.InputMismatchException;
import java.util.Scanner;
/**
* 多重catch塊
*/
public class testException {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("請輸入被除數");
/*把容易出錯的程式碼發入try中*/
try {
int num = scanner.nextInt();
System.out.println("請輸入除數");
int num2 = scanner.nextInt();
System.out.println(String.format("%d/%d=%d",num,num2,num/num2));
/*用多重catch來捕捉異常*/
}catch (InputMismatchException e){
System.out.println("被除數和除數必須是整數");
}catch (ArithmeticException e){
System.out.println("除數不能為零");
}catch (Exception e){
System.out.println("其他未知錯誤");
}finally {
System.out.println("感謝使用哦");
}
}
}
被除數不是整數,就會丟擲InputMismatchException這個異常:
被除數為0,就會丟擲ArithmeticException 這個異常:
在使用多重catch塊時,catch塊的排列順序必須是從子類到父類,最後一個一般是Exception類;
宣告異常——throws:
如果在一個方法體中丟擲了異常,我們希望呼叫著能夠及時的捕獲異常,那麼如何通知呼叫著呢?java語言中通過關鍵字throws宣告某個方法可能丟擲的各種異常throws可以同時宣告多個異常中間用逗號隔開。
把執行程式碼放在divide()方法中,並在方法的引數列表後通過throws宣告異常,然後在main()方法中呼叫該方法,此時main()方法就知道divide()方法中丟擲了異常,可以採取以下兩種方式進行處理。
- 通過try-catch捕獲並處理異常
- 通過throws繼續宣告異常,如果呼叫者不打算處理該異常,這可以繼續通過throws宣告,讓上一級呼叫者處理異常,main()方法宣告的異常將由java虛擬機器來處理。
通過try-catch捕獲並處理異常
import java.util.InputMismatchException;
import java.util.Scanner;
/**
* 使用throws宣告異常
*/
public class testException {
public static void main(String[] args) {
/*通過try-catch捕獲並處理異常*/
try {
divide();
/*用catch來捕捉異常*/
}catch (Exception e){
System.out.println("出現錯誤,被除數和除數必須是整數或被除數不能為零");
}finally {
System.out.println("感謝使用哦");
}
}
/*把執行程式碼放在divide()方法中*/
public static void divide() throws Exception{
Scanner scanner = new Scanner(System.in);
System.out.println("請輸入被除數");
int num = scanner.nextInt();
System.out.println("請輸入除數");
int num2 = scanner.nextInt();
System.out.println(String.format("%d/%d=%d",num,num2,num/num2));
}
}
通過throws繼續宣告異常
import java.util.Scanner;
/**
* 使用throws宣告異常
*/
public class testException {
/*通過throws繼續宣告異常*/
public static void main(String[] args) throws Exception {
divide();
}
/*把執行程式碼放在divide()方法中*/
public static void divide() throws Exception{
Scanner scanner = new Scanner(System.in);
System.out.println("請輸入被除數");
int num = scanner.nextInt();
System.out.println("請輸入除數");
int num2 = scanner.nextInt();
System.out.println(String.format("%d/%d=%d",num,num2,num/num2));
}
}
丟擲異常throw
既然可以捕獲到各種型別的異常,那麼這些異常是在那些地方丟擲的呢?
出來系統自動丟擲異常外,在程式設計過程中,我們往往遇到這樣的情形,有些異常是系統無法發現的並解決的,如年齡不在正常範圍內,性別不是男或女等,此時需要程式猿而不是系統丟擲異常,把問題提交給呼叫者去解決。
在java語言中,可以使用throw關鍵字來自行丟擲異常,示例程式碼:
/**
* 使用throw丟擲異常
*/
public class testException {
String name = "小明";//姓名
int age = 0;//年齡
String sex = "男"; //性別
public static void main(String[] args){
/*捕獲throw丟擲的異常*/
testException testException = new testException();
try {
testException.setSex("Male");
testException.print();
/*用catch來捕捉異常*/
}catch (Exception e){
e.printStackTrace();
}
}
/*設定性別*/
public void setSex(String sex) throws Exception{
if("男".equals(sex) || "女".equals(sex)){
this.sex = sex;
}else {
/*使用throw丟擲異常*/
throw new Exception("性別必須是男或女");
}
}
/*輸出基本資訊*/
public void print(){
System.out.println(this.sex+this.age+"歲");
}
}
throw和throws的區別表現在以下三個方面:
- 作用不同:throw用於在程式中丟擲異常,throws用於宣告在該方法內丟擲了異常。
- 使用的位置不同:throw位於方法體內部,可作為單獨語句使用、throws必須跟在方法列表引數後面,不能單獨使用。
- 內容不同:throw丟擲一個異常物件,而且只能是一個,throws跟異常類,而且可以跟多個異常類。
異常的分類:
java的異常體系包括許多異常類,他們之間存在繼承關係。如圖:
- Throwable是 Java 語言中所有錯誤或異常的超類。下一層分為Error和Exception
- Error類是指java執行時系統的內部錯誤和資源耗盡錯誤。應用程式不會丟擲該類物件。如果出現了這樣的錯誤,除了告知使用者,剩下的就是盡力使程式安全的終止。
- Exception又有兩個分支,一個是執行時異常RuntimeException,如:NullPointerException、ClassCastException;一個是檢查異常CheckedException,如I/O錯誤導致的IOException、SQLException。
總結:
異常是由java應用程式丟擲和處理的非嚴重錯誤Checked異常和執行時異常兩大類。
Checked異常必須捕獲或者宣告丟擲否則無法通過編譯。執行時異常不要求必須捕獲或者宣告丟擲。
java的異常處理是通過五個關鍵字來實現的:
try、catch、finally、thorw和thorws
即使在try塊、catch塊中存在return語句,finally塊中的語句也會被執行,finally塊中的語句不被執行的唯一情況是在在異常處理程式碼中執行System.exit(1)。
可以在同一個try塊語句後面跟多個catch語句塊,分別處理不同的異常,但排序順序必須是從特殊到一般,最後一個一般為Exception類。