天天看點

異常詳解及自定義異常和注意事項

異常的概述

異常就是Java程式在運作過程中出現的錯誤。      

異常的分類

通過API檢視Throwable      
1.Error
		 伺服器當機,資料庫崩潰等
     2.Exception      

異常的繼承體系

* Throwable
		* Error	
		* Exception
			* RuntimeException運作時異常,我們最容易犯的錯誤      

JVM預設是如何處理異常的

main函數收到這個問題時,有兩種處理方式:
		a:自己将該問題處理,然後繼續運作
		b:自己沒有針對的處理方式,隻有交給調用main的jvm來處理
			* jvm有一個預設的異常處理機制,就将該異常進行處理.
			* 并将該異常的名稱,異常的資訊.異常出現的位置列印在了控制台上,同時将程式停止運作      

測試異常處理

public static void main(String[] args) {
		// TODO Auto-generated method stub
		int x = 10 / 0;
		System.out.println(x);
		//Exception in thread "main" java.lang.ArithmeticException: / by zero
	}
           
public class ArithmeticExceptionextends RuntimeException
	 當出現異常的運算條件時,抛出此異常。例如,一個整數“除以零”時,抛出此類的一個執行個體。       

異常處理的兩種方式

try…catch…finally

try catch
	try catch finally
	try finally       

throws

try...catch處理異常的基本格式
			try…catch…finally      
try:用來檢測異常的
       
catch:用來捕獲異常的
finally:釋放資源
當通過trycatch将問題處理了,程式會繼續執行      
public static void main(String[] args) {
		try{
			int x = 10/0;
			System.out.println(x);
		}catch(ArithmeticException e) {	
			//ArithmeticException a = new ArithmeticException();
			System.out.println("出錯了,除數為零了");
			System.out.println(e);//java.lang.ArithmeticException: / by zero
		}
	}
           

try...catch的方式處理多個異常

JDK7以後處理多個異常的方式及注意事項	  
		安卓,用戶端開發,如何處理異常?try{}catch(Exception e){}
	 	ee,服務端開發,一般都是底層開發,從底層向上抛
	 try後面如果跟多個catch,那麼小的異常放前面,大的異常放後面,根據多态的原理,如果大的放前面,就會将所有的子類對象接收
  後面的catch就沒有意義了      
public static void main(String[] args) {
		int a = 10;
		int b = 0;
		int[] arr = {11,22,33,44,55};
		
		try {
			System.out.println(a / b);
			System.out.println(arr[10]);
			arr = null;
			System.out.println(arr[0]);
		} catch (ArithmeticException e) {
			System.out.println("除數不能為零");
		} catch (ArrayIndexOutOfBoundsException e) {
			System.out.println("索引越界了");
		} catch (Exception e) {	//Exception e = new NullPointerException();
			System.out.println("出錯了");
		}
		System.out.println("over");
		
		
		int a1 = 10;
		int b1= 0;
		int[] arr1 = {11,22,33,44,55};
		//JDK7如何處理多個異常
		try {
			System.out.println(a1 / b1);
			System.out.println(arr1[10]);
		} catch (ArithmeticException | ArrayIndexOutOfBoundsException e) {
			System.out.println("出錯了");
		} 
	}
           

編譯期異常和運作期異常的差別

* Java中的異常被分為兩大類:編譯時異常和運作時異常。
	* 所有的RuntimeException類及其子類的執行個體被稱為運作時異常,其他的異常就是編譯時異常
	* 編譯時異常
		* Java程式必須顯示處理,否則程式就會發生錯誤,無法通過編譯
	* 運作時異常
		* 無需顯示處理,也可以和編譯時異常一樣處理      

Throwable的幾個常見方法

getMessage()
				* 擷取異常資訊,傳回字元串。
		:toString()
				* 擷取異常類名和異常資訊,傳回字元串。
		printStackTrace()
				* 擷取異常類名和異常資訊,以及異常出現在程式中的位置。傳回值void。      
public static void main(String[] args) {
		try {
			System.out.println(1/0);
		} catch (Exception e) {	
			//Exception e = new ArithmeticException("/ by zero");
			System.out.println(e.getMessage());	//擷取異常資訊/ by zero
			System.out.println(e); 	//調用toString方法,列印異常類名和異常資訊
			//java.lang.ArithmeticException: / by zero
			e.printStackTrace();//jvm預設就用這種方式處理異常
			//java.lang.ArithmeticException: / by zero
			//at a.main(a.java:112)
		}
	}
           

throws的方式處理異常

*定義功能方法時,需要把出現的問題暴露出來讓調用者去處理。
那麼就通過throws在方法上辨別。
案例示範
	* 舉例分别示範編譯時異常和運作時異常的抛出
		* 編譯時異常的抛出必須對其進行處理
		* 運作時異常的抛出可以處理也可以不處理
 @throws Exception       
public class a {
	public static void main(String[] args) throws Exception {
		Person p = new Person();
		p.setAge(-17);
		System.out.println(p.getAge());
	}	
}
class Person {
	private String name;
	private int age;
	public Person() {
		super();
		
	}
	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	/*public void setAge(int age) throws Exception {
		if(age >0 && age <= 150) {
			this.age = age;
		}else {
			//Exception e = new Exception("年齡非法");
			//throw e;
			throw new Exception("年齡非法");
		}
	}*/
	public void setAge(int age)  {
		if(age >0 && age <= 150) {
			this.age = age;
		}else {
			throw new RuntimeException("年齡非法");
		}
	}
}
           

throw的概述以及和throws的差別

throw的概述

在功能方法内部出現某種情況,程式不能繼續運作,需要進行跳轉時,就用throw把異常對象抛出。      

throws和throw的差別

:throws
		* 用在方法聲明後面,跟的是異常類名
		* 可以跟多個異常類名,用逗号隔開
		* 表示抛出異常,由該方法的調用者來處理
	throw
		* 用在方法體内,跟的是異常對象名
		* 隻能抛出一個異常對象名
		* 表示抛出異常,由方法體内的語句處理      

finally的特點及作用

特點

被finally控制的語句體一定會執行
	特殊情況:在執行到finally之前jvm退出了(比如System.exit(0))      

作用

用于釋放資源,在IO流操作和資料庫操作中會見到		      
return語句在執行之前看一看有沒有finally,如果有就将finally執行後在徹底傳回      
public class b {
	public static void main(String[] args) {
		try {
			System.out.println(10/0);
		} catch (Exception e) {
			System.out.println("除數為零了");
			//System.exit(0);//退出jvm虛拟機
			return;
		} finally {
			System.out.println("看看我執行了嗎");
		}
	}
}
           

finally關鍵字的面試題

面試題1 final,finally和finalize的差別      
final可以修飾類,不能被繼承
		final可以修飾方法,不能被重寫
		final可以修飾變量,隻能指派一次
		 
		finally是try語句中的一個語句體,不能單獨使用,用來釋放資源

		finalize是一個方法,當垃圾回收器确定不存在對該對象的更多引用時,由對象的垃圾回收器調用此方法。
			protected void finalize() throws Throwable
			當垃圾回收器确定不存在對該對象的更多引用時,由對象的垃圾回收器調用此方法。
			子類重寫 finalize 方法,以配置系統資源或執行其他清除。 
      

面試題2    如果catch裡面有return語句,請問finally的代碼還會執行嗎?如果會,請問是在return前還是return後。

先建立好傳回路徑,然後執行finally的代碼,最後徹底傳回      
public class c {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Demo d = new Demo();
		System.out.println(d.method());//30
	}

}

class Demo {
	//@SuppressWarnings("finally")
	public int method() {
		int x = 10;
		try {
			x = 20;
			System.out.println(1/0);
			//return x;
			return x;
		} catch (Exception e) {
			x = 30;
			return x;
		} finally {
			x = 40;//catch已經建立好傳回路徑,在此改變x的值不會影響catch的傳回值
			//return x;//40
			//千萬不要在finally裡面寫傳回語句,因為finally的作用是為了釋放資源,是肯定會執行的
			//如果在這裡面寫傳回語句,那麼try和catch的結果都會被改變,是以這麼寫就是犯罪
		}
	}
}
           

自定義異常概述和基本使用

為什麼需要自定義異常

易于排錯,望名生義(取決于名字)      

自定義異常概述

繼承自Exception
	繼承自RuntimeException
	重寫異常的空參有參構造,參數向上傳遞super      

自定義異常的基本使用

public class a {  
    public static void main(String[] args) throws Exception {  
        Person p = new Person();  
        p.setAge(-17);  
        System.out.println(p.getAge());  
    }     
}  
/*
 * 自定義異常
 * 也可以繼承 RuntimeException運作時異常,編譯時不用處理
 * */
class AgeOutOfBoundsException extends Exception {
	public AgeOutOfBoundsException() {
		super();	
	}

	public AgeOutOfBoundsException(String message) {
		super(message);	
	}
}

class Person {  
    private String name;  
    private int age;  
    public Person() {  
        super();  
          
    }  
    public Person(String name, int age) {  
        super();  
        this.name = name;  
        this.age = age;  
    }  
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
    public int getAge() {  
        return age;  
    } 
    //異常抛出處理,檢視Exception
    public void setAge(int age) throws AgeOutOfBoundsException  {  
        if(age >0 && age <= 150) {  
            this.age = age;  
        }else {  
          // throw new AgeOutOfBoundsException();  
        	throw new AgeOutOfBoundsException("年齡錯誤");
        }  
    }  
}  
           

異常的注意事項及如何使用異常處理

異常注意事項

a:子類重寫父類方法時,子類的方法必須抛出相同的異常或父類異常的子類。
	b:如果父類抛出了多個異常,子類重寫父類時,隻能抛出相同的異常或者是他的子集,子類不能抛出父類沒有的異常
	c:如果被重寫的方法沒有異常抛出,那麼子類的方法絕對不可以抛出異常,
	     如果子類方法内有異常發生,那麼子類隻能try,不能throws      

如何使用異常處理

原則:如果該功能内部可以将問題處理,用try,如果處理不了,交由調用者處理,這是用throws
	差別:
		後續程式需要繼續運作就try
		後續程式不需要繼續運作就throws      

如果JDK沒有提供對應的異常,需要自定義異常。