Java異常

一、異常?

java系統中將java.lang.Throwable類作為異常的最根類

[java.lang.Throwable是所有異常或錯誤的頂級類,可以處理任何異常]

* java.lang.Throwable
 * 		|-----java.lang.Error:一般不編寫針對性的代碼進行處理。
 * 		|-----java.lang.Exception:可以進行異常的處理
 * 			|------編譯時異常(checked)
 * 					|-----IOException
 * 						|-----FileNotFoundException
 * 					|-----ClassNotFoundException
 * 			|------運行時異常(unchecked,RuntimeException)
 * 					|-----NullPointerException
 * 					|-----ArrayIndexOutOfBoundsException
 * 					|-----ClassCastException
 * 					|-----NumberFormatException
 * 					|-----InputMismatchException
 * 					|-----ArithmeticException

二、異常分類

Throwable是所有異常或錯誤的頂級類,可以處理任何異常.

因為處理範圍過大,操作不方便,Java提供兩個子類:Exception和Error

異常分為: Exception(可以治療) 和 Error(不治之症)

1. Error:

通常指 java系統出現的錯誤,與java程序無關. 無法使用代碼進行維護或修改錯誤.

2. Exception:

通常指 java程序出現的錯誤,可以使用代碼進行修改或維護.[通常值學習/研究 Exception.]

Exception的分類: [根據 編譯時 是否檢查 含有XX異常分類]

須查異常[非運行時異常]: 指 java文件編譯為class文件時, 需要檢查的異常.

不須查異常[運行時異常]: 指 java文件編譯為class文件時, 不需要檢查的異常.

3. 哪些異常屬於須查異常,哪些異常屬於不須查異常?

Exception及其子類[不含RuntimeException]都屬於須查異常[非運行時異常]

RuntimeException及子類屬於不須查異常也就是運行時異常

4. 常見的須查異常(編譯時異常):

語法錯誤 路徑錯誤 等等

5. 常見的不須查異常(運行時異常):

數組下標越界:java.lang.ArrayIndexOutOfBoundsException,Java程序試圖訪問不存在的索引對應的元素.

被除數為0: java.lang.ArithmeticException: / by zero,在計算機中,被除數不能為0.

空指針:java.lang.NullPointerException,Java程序試圖去訪問不存在的對象的屬性或方法,因此報錯.

三、異常處理

使用try-catch-finally處理編譯時異常,使得程序在編譯時就不報錯,但是運行是仍然可能報錯

開發中由於運行時異常常見,通常不針對運行時異常try-catch-finally處理,而針對編譯時異常,一定要考慮異常的處理

throws的方式知識將異常拋給了方法的調用者,並沒有真正的將異常處理

1. 第一種: [積極處理]

try{

存放可能發生異常的代碼,try代碼塊將自動捕捉異常

}catch(異常類型  參數){

與發生的異常進行匹配,匹配上後將執行此處代碼

}catch(異常類型  參數){

與發生的異常進行匹配,匹配上後將執行此處代碼

}finally{

作為程序最後執行的代碼,一定會執行,即使try和catch裏面有return或異常

}

說明:

  • try,catch,finally代碼塊不能單獨使用,必須混合. 常見組合方式:try,catch,finally 或 try catch 或 try finally
  • try代碼塊必須含有,catch代碼可以含有N個.finally代碼塊可以含有0或1個,且必須放在try和catch的後面.

原理:

  • java程序執行try代碼塊中的代碼,如果發生異常,將被try代碼塊捕獲,
  • try代碼塊捕獲異常後, 將於之後的catch代碼塊進行異常類型匹配,如果匹配上異常類型,將執行執行此處的catch代碼塊,不再向下繼續匹配.
  • try代碼塊捕獲異常後,與所有的catch代碼塊的異常類型都不匹配,該異常將交給java系統處理[直接結束程序的執行]無論程序是否發生異常,異常是否處理成功,都將執行finally代碼塊[通常用於執行關鍵性的代碼: 關閉資源等等,降低程序的損失

注意: 當有多個catch代碼塊時,將處理範圍大的異常放在後面.

try中的異常對象匹配到某一個catch時,就會進入到catch中進行異常的處理,一旦處理完成,就退出當前的try-catch結構(在沒有寫finally的時候),繼續執行其後的代碼

常用的處理方式:

都是打印錯誤信息,方式不同

public void test1() {
		String str = "abc";
		try {
			int num = Integer.parseInt(str);
		}catch(Exception e) {
			// 1. System.out.println(e.getMessage());
            
			// 2. e.printStackTrace();
		}
	}

快捷操作

2. 第二種: [消極處理]

格式: 

權限.... 方法名(參數類型 參數名,參數類型 參數名,...) throws 異常類型,...{

方法體

}

原理:

  • 當前方法體中將異常拋出到方法調用處,在方法調用的地方必須處理當前異常.
  • 方法調用處可以處理該異常,也可以繼續向方法外拋出異常.[如果main函數中也沒有處理該異常,該異常將拋給Java系統,Java系統將以”粗暴的方式”處理,直接結束程序的執行]
  • 異常後面的代碼就不會再執行了

方法重寫的規則之一:

類重寫的方法拋出的異常類型不大於父類被重寫的方法拋出的異常類型

import java.io.FileNotFoundException;
import java.io.IOException;

public class OverrideTest {
	
	public static void main(String[] args) {
		OverrideTest test = new OverrideTest();
		test.display(new SubClass());
	}

	
	public void display(SuperClass s){
		try {
			s.method();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

class SuperClass{
	
	public void method() throws IOException{
		
	}	
}

class SubClass extends SuperClass{
	public void method()throws FileNotFoundException{
		
	}
}

3. 開發中如何選擇使用try-catch-finally 還是使用throws?

  • 如果父類中被重寫的方法沒有throws方式處理異常,則子類重寫的方法也不能使用throws,意味着如果子類重寫的方法中有異常,必須使用try-catch-finally方式處理。

  • 執行的方法a中,先後又調用了另外的幾個方法,這幾個方法是遞進關係執行的。我們建議這幾個方法使用throws的方式進行處理。而執行的方法a可以考慮使用try-catch-finally方式進行處理。

四、手動拋出異常

throw

public class StudentTest {
	
	public static void main(String[] args) {
		try {
			Student s = new Student();
			s.regist(-1001);
			System.out.println(s);
		} catch (Exception e) {
//			e.printStackTrace();
			System.out.println(e.getMessage());
		}
	}
	
}


class Student{
	
	private int id;
	
	public void regist(int id) throws Exception {
		if(id > 0){
			this.id = id;
		}else{
//			System.out.println("您輸入的數據非法!");
			//手動拋出異常對象,運行時異常,可以不用try-catch
//			throw new RuntimeException("您輸入的數據非法!");
            
            // 必須進行try-catch
			throw new Exception("您輸入的數據非法!");
            
			//錯誤的
//			throw new String("不能輸入負數");
		}
		
	}

	@Override
	public String toString() {
		return "Student [id=" + id + "]";
	}
	
	
}

五、 自定義異常

如何自定義異常類?

  • 繼承於現有的異常結構:RuntimeException 、Exception
  • 提供全局常量:serialVersionUID
  • 提供重載的構造器
public class MyException extends Exception{
	
	static final long serialVersionUID = -7034897193246939L;
	
	public MyException(){
		
	}
	
	public MyException(String msg){
		super(msg);
	}
}

此時使用自己定義的異常類

package com.atguigu.java2;

public class StudentTest {
	
	public static void main(String[] args) {
		try {
			Student s = new Student();
			s.regist(-1001);
			System.out.println(s);
		} catch (Exception e) {
//			e.printStackTrace();
			System.out.println(e.getMessage());
		}
	}
	
}


class Student{
	
	private int id;
	
	public void regist(int id) throws Exception {
		if(id > 0){
			this.id = id;
		}else{
			throw new MyException("不能輸入負數");
		}
	}

	@Override
	public String toString() {
		return "Student [id=" + id + "]";
	}
	
	
}

六、問題

進入A—-用A方法—-製造異常—-進入方法B—–調用B

1. 請解釋Error和Exception的區別?

  • Error:指的是JVM錯誤,這個時候的程序並沒有執行,無法處理;
  • Exception:指的是程序之中出現的錯誤信息,可以進行異常處理,主要關心Exception。

2. 請解釋java之中的異常處理流程

  • 如果程序之中產生了異常,那麼會自動的由JVM根據異常的類型,實例化一個指定異常類的對象;
  • 如果這個時候程序之中沒有任何的異常處理操作,則這個異常類的實例化對象將交給JVM進行處理,而JVM的默認處理方式就是進行異常信息的輸出,而後中斷程序執行
  • 如果程序之中存在了異常處理,則會由try語句捕獲產生的異常類對象
  • 與try之後的每一個catch進行匹配,如果匹配成功,則使用指定的catch進行處理,如果沒有匹配成功,則向後面的catch繼續匹配,如果沒有任何的catch匹配成功,則這個時候將交給JVM執行默認處理
  • 不管是否有異常都會執行finally程序,如果此時沒有異常,執行完finally,則會繼續執行程序之中的其他代碼,如果此時有異常沒有能夠處理(沒有一個catch可以滿足),那麼也會執行finally,但是執行完finally之後,將默認交給JVM進行異常的信息輸出,並且程序中斷

3. 請解釋一下RuntimeException和Exception的區別?請列舉出幾個常見的RuntimeException

七、總結

throw 和 throws區別:
throw 表示拋出一個異常類的對象,生成異常對象的過程。聲明在方法體內。
throws 屬於異常處理的一種方式,聲明在方法的聲明處。

Tags: