黑馬程序員_Java基礎_異常

一,異常的概念:

在沒有學習異常之前,我們所有的程序都是默認在理想狀態下運行的,在實際開發中可能存在各種各樣的問題,比如用戶輸入的數值不正確,,格式不正確,都會引起程序運行的錯誤。所謂的異常就是程序運行時出現的不正常的情況。異常也是現實生活中一個個具體的事物,java中的異常時通過java類的形式進行描述,並且封裝成對象的。異常對象都是派生於Throwable類的一個實例。

二,java中的異常的體系結構:

Throwable

|——Error

|——Exception

|——RuntimeException

|——IOException

Error是嚴重異常,是JVM處理不了的異常,所以用戶也處理不了,所以我們不需要去管。當然這種嚴重異常出錯的概率也是比較小的。我們重點討論的是Exception,需要我們程序員去處理的東西。

 

1RuntimeException

Exception的一個特殊子類異常RuntimeException(運行時異常),該異常在函數

部通過throw關鍵字拋出後可以不用再函數上聲明,編譯一樣會通過,如果在函數上聲明,調用者不用進行處理,也會通過;(面試常考)

 

2,體系中的省略號是指繼承Exception,就是Exception的除RuntimeException的子類。繼承Exception的子類,在函數內部拋出異常對象如果不在函數上聲明,則編譯不能通過,聲明之後調用者不進行處理,編譯也不能通過;

之所以不在函數上聲明是因爲不希望調用者處理,當該異常發生時,希望程序停止,因爲在運行時出現了無法繼續運行的情況,這時就需要停止程序對代碼進行修改;

 

3,異常體系的特點:異常體系中所有類以及建立的對象都具有可拋性。

也就是說可以被throwthrows關鍵字操作;只有異常體系具備這個特點;

 

throwthrows的用法:

throw定義在函數內部,用於拋出異常對象;

throws定義在函數上,用於拋出異常類,可以拋出多個用逗號隔開;

 

當內容有throw拋出的異常對象,並未進行try處理必須要在函數上用throws關鍵字拋出(聲明),否則編譯失敗;

注意:函數內如果拋出的是RuntimeException,函數上可以不用聲明。

 

三,異常的處理:

1,如果在函數上面進行聲明過的異常,也就是用關鍵字throws在函數上面聲明的異常,當在某個方法中調用這樣的方法的時候,要麼執行try...catch處理,要麼向上一級拋出去,也就是在這個函數上面繼續throws。這一點我們在使用java文檔的時候可能會看到很多。當然不是所有的異常都可以進行throws的,將會在後面的筆記中總結到。

2,異常的分類:有兩種:

1),編譯時被檢測異常;

該異常在編譯時如果沒有處理(沒有拋,也沒有try)則編譯失敗。

該異常被標示,代表可以被處理;

2),運行時異常,編譯時不檢測;

編譯時不需要處理,編譯不檢查;

該異常發生時,建議不要處理,讓程序停止,需要對代碼進行修正;

 

3,異常處理的語句:

try{

 

需要被檢測的代碼;

 

}catch(){

 

處理異常的代碼;

}finally{

 

一定會執行的代碼;

 

}

 

三種形式:

1,形式一:

try{

 

}catch(){

 

}finally{

 

}

 

2,形式二

try{

 

}catch(){

 

}

 

3,形式三

try{

 

}finally{

 

}

 

Finally特點:

1,fianlly裏面通常定義的是關閉資源的代碼,因爲資源必須釋放;

2),finally只有一種情況下不會執行,當執行到System.exit(0)時,JVM結束,finally不會執行;

 

四,自定義異常方法:

1,自定義異常:是按照java的面型對象思想,將程序的特有問題進行封裝;

 

在自定義異常中可以有兩種選擇,要麼繼承Exception要麼繼承RuntimeException

本程序重點講解這兩種用戶自定義異常父類的不同。

 

1,爲了讓該自定義類具有可拋性;

2),讓該類具備操作異類的共性方法;

 

當要定義自定義異常信息的時候,可以使用父類已經定義好的功能。異常信息傳遞給父類的構造函數;(多查看java文檔)

 

class MyException extends Exception

{

MyException(String message) {

super(message);

}

}

 

示例一:編寫一個程序,計算一個數除以另外一個數,在相除的時候,除數可能爲零。定義一個負數異常繼承Exception,當除數爲0的時候,拋出異常,打印在控制檯,並且終止整個程序,下面的程序不在執行。


class FushuException extends Exception {
	/*
	 * private String msg; FushuException(String msg) { this.msg = msg; }
	 * 
	 * public String getMessage() { return msg; }
	 */

	private int value;

	FushuException(String msg, int value) {
		super(msg);
		this.value = value;
	}

	public int getValue() {
		return value;
	}
}

class Demon5 {

	public int account(int a, int b) throws FushuException {
		if (b < 0)
			throw new FushuException("出現了負數的情況;", b);// 手動通過關鍵字自定義一個負數異常;
		int c = a / b;
		return c;
	}
}

class ExceptionTest {
	public static void main(String[] args) {
		Demon5 d = new Demon5();
		try {
			System.out.println(d.account(4, -5));
		} catch (FushuException e) {
			System.out.println(e.toString());
			// System.out.println("除數不能爲負數!");
			System.out.println("錯誤的負數是" + e.getValue());
		}
	}
}

示例二:將示例一的程序進行簡化,可以直接將負數異常通過throw關鍵字在函數內部拋出,這時候就不需要在函數上面通過throws拋給上一級。下面的程序負數異常時繼承自RuntimeException,當然也可以不用定義,直接throw new RuntimeException(異常提示);


class Test3 {
	int div(int a, int b) {
		if (b < 0)
			throw new FushuException2("除數爲負數了;");// 該異常發生後計算無法繼續,希望程序停止,不需要在
			// 函數上聲明;
			// 可以不用定義FushuException2,直接throw new RuntimeException("除數爲零");
		return a / b;
	}
}

class ExceptionDemon {
	public static void main(String[] args) {
		Test6 t6 = new Test6();
		int c = t6.div(5, -8);
		System.out.println(c);
	}
}

示例三:自定義繼承自ExceptionRuntimeException的綜合例子。

需求:老師用電腦上課;(面向對象思想:名詞提煉法)

老師類,電腦類

 

可能出現的異常:

電腦藍屏;--->可以解決,重啓電腦,繼續上課;

電腦冒煙;--->老師不能解決,該異常跟老師沒關係,如果繼續往外拋,別的老師也解決不了,此時拋出老師自己的異常,不能上課了;當校長接收到這一異常時可以解決,就是放假休息的,等待電腦修好了繼續上課;


class LanpingException extends Exception {
	LanpingException(String msg) {
		super(msg);
	}
}

class MaoyanException extends RuntimeException {
	MaoyanException(String msg) {
		super(msg);
	}
}

class NoplanException extends Exception {
	NoplanException(String msg) {
		super(msg);
	}
}

class Computer {
	private int state = 3;

	public void run() throws LanpingException, MaoyanException {
		if (state == 1)
			System.out.println("電腦運行。。。");
		else if (state == 2)
			throw new LanpingException("電腦藍屏了。。。請重啓");
		else if (state == 3)
			throw new MaoyanException("電腦冒煙。。。");

	}

	public void reset() {
		System.out.println("電腦重啓。。。");
	}
}

class Teacher {
	private Computer cmpt;
	private String name;

	Teacher(String name) {
		this.name = name;
		cmpt = new Computer();
	}

	public void teach() throws NoplanException {
		try {
			cmpt.run();
		} catch (LanpingException e) {
			cmpt.reset();
		} catch (MaoyanException e) {
			test();
			System.out.println(e.toString());
			throw new NoplanException("無法繼續上課。。。");
		}
		System.out.println(name + "老師講課。。。");
	}

	public void test() {
		System.out.println("學生做練習。。。");
	}
}

class ExceptionExercise {
	public static void main(String[] args) {
		Teacher t = new Teacher("李");
		try {
			t.teach();
		} catch (NoplanException e) {
			System.out.println("全體放假。。。");
		}
	}
}

總結:前面已經給出了異常處理的幾種代碼的形式,其中finally也是十分重要的一個知識點。finally語句裏面的內容無論什麼情況都會執行;它的應用主要是在數據庫上;因爲數據庫的連接資源是有限的,當發生異常時如果程序停止的話,數據庫的連接如果沒有斷開,將會佔用很多資源,這是finally語句就起到很大的作用。


public void method() throws SQLException {
	連接數據庫;
	數據庫的操作;
	關閉數據庫;//該動作無論數據庫的操作是否成功,都必須進行;
 
 
	try{
		連接數據庫;
		數據庫的操作;//throw new SQLException();
	}catch(SQLException e) {
		...
	}finally {
		關閉數據庫;
	}
}
try...catch的另外幾種格式:
	try{
		...
	}catch(Exception e) {
		...
	}
	 
	 
	try{
		...
	}catch(Exception e) {
		...
	}finally {
		...
	}
	 
	 
	try{
		...
	}finally {  //finally用於關閉資源
		...
	}//記住catch是用於處理異常,如果沒有catch說明此異常沒有被處理過,此時就必須聲明出去;

五,子類覆蓋父類時異常的處理規則:

1,子類在覆蓋父類時如果父類的方法拋出異常,那麼子類的覆蓋方法,只能拋出父類的異常或者該異常的子類。

2,如果在父類方法中拋出多個異常,子類再覆蓋時只能拋出父類異常的子異常,或者不拋。例如:父類方法有A,B,C,D,E這幾個異常,子類再覆蓋該方法時只能拋出這五個異常的子集或者不拋。

3,如果父類或接口的方法中沒有拋出異常,那麼子類在覆蓋該方法時也不可以拋出異常。如果子類方法發生了異常就必須用try語句解決,絕對不能向外拋。


示例分析:
class AException extends Exception {
	...
}
 
class BException extends AException {
	...
}
 
class CException extends Exception{
	...
}
 
class Fu {
	public void show() throws AException {
		...
	}
}

class Zi extends Fu
 {
	public void show() throws AException {//或者拋出BException,但是絕對不能拋CException,如果發生
	//CException那麼就必須在該方法中用try語句處理掉這個異常;
		...
	}
 }
 
public class ExceptionTestDemon2 {
	public static void main(String[] args) {
		...
	}
}

六,最後給出異常的綜合應用的一個例子來說明異常的應用:

需求:計算一個園和長方形的面積;對於非法值得輸入可以視爲獲取面積出現的問題;問題可以用異常來表示。


//首先自定義一個異常
class FushuException extends RuntimeException {
	FushuException(String message) {
		super(message);
	}
}
//定義一個抽象類,將打印面積的方法放在抽象類中,子類必須重寫該方法
abstract class Area {
	public abstract void getArea();
}

//計算矩形面積
class Rect extends Area {
	private double width, high;

	Rect(double width, double high) {
		if (width < 0 || high < 0)
			throw new FushuException("長方形的長或寬不能爲零。。。");
		// 這裏當然也可以用if語句來判斷然後給出錯誤提示,但是在java中這樣做是不提倡的;
		// 因爲這樣寫的話錯誤處理代碼和正常流程代碼聯繫非常緊密,閱讀性比較差;正真做項目時
		// 如果用if語句,那麼if裏面將會是一大片處理代碼,閱讀性非常差;而異常處理Exception的
		// 好處在於可以將異常處理代碼和正常流程代碼分離開來,當問題發生時,可以不修改正常流程代碼
		// 而直接到異常處理代碼區修改異常處理代碼;
		this.width = width;
		this.high = high;
	}

	public void getArea() {
		System.out.println(width * high);
	}
}

//計算圓面積
class Circle extends Area {
	private double radious;
	public static final double PI = 3.14;

	Circle(double radious) {
		if (radious < 0)
			throw new FushuException("圓半徑爲負數。。。。");
		this.radious = radious;
	}

	public void getArea() {
		System.out.println(radious * radious * PI);
	}
}

class DoArea {
	public void doArea(Area a) {
		a.getArea();
	}
}

class ExceptionArea {
	public static void main(String[] args) {
		DoArea d = new DoArea();
		d.doArea(new Rect(2.0, 3.6));
		d.doArea(new Circle(-2));
	}
}





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章