黑馬程序員 Java面向對象——異常

面向對象

首先什麼都不說,Java是面向對象的語言,當然也對異常包裝成了對象(Throwable),方便了我們的使用,這個是必須的,咱們以後天天面向對象,當然現在我是沒有對象的,所謂對象就是女朋友。準備黑馬就業後纔去new 一個對象。

異常:就是程序在運行時出現不正常情況。

異常由來:

問題也是現實生活中一個具體的事物,也可以通過Java的類的形式進行描述。並封裝成對象。

其實就是Java對不正常情況進行描述後的對象體現。描述不正常的情況的類,就稱爲異常類。

不同的問題用不同的類進行具體的描述。比如角標越界異常,空指針異常等等。

問題很多,意味着描述的類也很多,將其共性進行向上抽取,形成了異常體系。

異常的好處:

(1)、將問題進行封裝。

(2)、將正常流程代碼和問題處理代碼相分離,方便於閱讀。

異常的體系

異常體系的特點:

子類的後綴名都是用父類名作爲後綴,閱讀性很強。

最終問題(Final 問題(當然放幾個洋屁嘛!當然不是放的很響))(不正常情況)就分成了兩大類。

Throwable

無論是Error,還是Exception

問題,問題發生就應該可以拋出,讓調用者知道並處理。  

該體系的特點就在於Throwable及其所有的子類都具有可拋性。

可拋性到底指的是什麼呢?throws  throw

怎麼體現可拋性呢?凡是可以被這兩個關鍵字所操作的類和對象都具備可拋性。

1, 一般不可處理的。Error

特點:是同Jvm拋出的嚴重性的問題。

通常出現重大問題如:運行的類不在在或者內存溢出等。

這種問題發生一般不針對性處理。直接修改程序。

錯誤:通常是不編寫代碼對其進行鍼對處理。

2,可以處理的。Exception

處理Exception異常有倆種方法:

一是:在運行時運行出現的一些情況,可以通過 try catch finally

二是:通過throws在函數上聲明。(如果函數內throw異常,那麼函數就必須聲明)

異常:是在運行時期發生的不正常情況..

處理異常(Exception)的幾種格式:

格式一:

try{

可能發生異常的代碼;

}

catch(接收捕獲異常類的對象 異常類引用變量){

處理代碼;

}

格式二:

try{

可能發生異常的代碼;

}
fianlly{

一定要執行的語句;(通常用於關閉資源)

}

格式三:

try{

可能發生異常的代碼;

}

catch(捕獲異常類的對象 異常類引用變量){

處理代碼;

}

finally{

一定要執行的語句;(通常用於關閉資源)

}

異常示例:

class Test {

public static void main(String[] args) {

int[] arr = {1,3,5,7,9};

try{

System.out.println(arr[5]);

}

catch (Exception e){

System.out.println("數組角標越界");

}
finally{

System.out.println("return 之前必須執行");

return ;

}

}

}


throw和throws的用法 

(1)、throw定義在函數內,用於拋出異常對象。

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

異常的選用:

當拋出的異常是調用者誤操作完成的,那麼繼承RuntimeException類,如果該異常的發生,就讓該程序停掉。

一般情況下繼承的都是Exception異常。


異常有兩種


編譯時異常:

該異常在編譯時,沒有處理(沒有拋出也沒有try),編譯失敗

運行是異常(編譯時不檢測):

在編譯時,不需要處理,編譯器不檢查

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


注意:

當函數內有throw拋出異常對象,並未進行try處理。必須要在函數上聲明,否則編譯失敗

Exception有一個特殊的子類,RuntiimeException

也就是說,函數內如果拋出的RuntimeException異常,函數上可以不用聲明。

例子:

class MyRutimeException extendsRuntimeException{

MyRutimeException(String msg){

super(msg);

}

}

class Test{

public static void main(String[] args) {

try{

show(true);

}

catch(MyRuntimeException e){

System.out.println(e.toString());

//這裏寫成e可不可以,當然是可以的,因爲默認就是toString()

}

}

public static void show(boolean b){

if(b)

throw new MyRutimeException("值爲true了");

}

}

注意

如果Exception在內部被解決,比如內部catch(捕獲)並對異常進行了處理,則該方法不用聲明異常。

記住一點,catch是用於處理異常,如果沒有catch就代表異常沒有被處理。

如果該異常是檢測,可以沒有catch語句。

當然:如果拋出的是多個異常,就要有幾個catch,也有簡單的做法,直接拋父類異常Exception


異常處理的原則:

1,函數內容如果拋出需要檢測的異常,那麼函數上必須要聲明。

       否則必須在函數內用try catch捕捉,否則編譯失敗。

2,如果調用到了聲明異常的函數,要麼try catch要麼throws,否則編譯失敗。

(如果調用的函數拋出異常,那麼調用者可以try catch也可以throws

(如果調用的是複寫父類的函數拋出異常,那麼調用者只能拋出父類同樣的異常,或者父類異常的子集)

3,什麼時候catch,什麼時候throws 呢?

功能內容可以解決,用catch

解決不了,用throws把異常告訴調用者,由調用者解決 。

4,一個功能如果拋出了多個異常,那麼調用時,必須有對應多個catch進行針對性的處理。

       內部有幾個需要檢測的異常,就拋幾個異常,拋出幾個,就對應有幾個catch

5,拋到最後拋給誰纔是個頭呢?答案是拋到虛擬機纔是頭。

fianlly 特殊之處:

finally語句中定義的是一定要執行的語句,通常用於關閉資源。(因爲資源必須釋放)

finally除非遇到System.exit(0);也是就虛擬機退出纔不會執行。

子類覆蓋父類時對異常處理的注意事項:

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

2、如果父類方法拋出多個異常,那麼子類再覆蓋該方法時,只能拋出父類異常的子集。

(也就是父類如果拋多個異常,那麼我們不能直接拋Exception異常。)

(如果拋一個異常的時候,是可以拋父類異常的)

3、如果父類或者接口的方法中沒有異常拋出,那麼子類在覆蓋方法時,也不可以拋出異常。

4、如果子類方發發生了異常,就必須要進行try處理,絕對不能拋。

5、如果在子類的覆蓋方法確實需要拋出非父類的異常或者該異常的子類,則必須在內部解決。

自定義異常

定義類繼承Exception或者RuntimeException

(其實我們這樣也是用面向對象思考問題,把我們程序設計中可能出現的問題進行了封裝。)

(1)、爲了讓該自定義類具備可拋性

(2)、讓該類具備操作異常的共性方法

(3)、當要自定義異常的信息時,可以使用父類已經定義好的功能,異常信息傳遞給父類的構造函數。

例子

import Java.util.Random;

class MyException extends Exception{

MyException(String message){

super(message);//父類帶參數的構造函數

}

}

/*

在我們的程序中,數組爲空就會發生空指針異常。

*/

class Test {

public static void main(String[] args) /*throws Exception ...當然這裏也可以直接把問題拋出去*/{

//定義了一個空數組

int[] arr =new int[0];

try{

/*

對調用的方法進行try catch處理。

*/

method(arr);

}

catch(Exception e){

/*

跟蹤打印下拋異常的類和問題

*/

System.out.println(e.toString());//MyException: 空指針異常

}

}

/*

定義一個方法,打印一下數組,對數組進行空指針判斷,如果爲空發生異常

*/

public static void method(int[] arr)throws Exception{

if(arr.length==0)

/*

如果數組爲空,就在函數內拋出異常,在函數上聲明拋出的異常。

*/

throw new MyException("空指針異常");

}

System.out.print("[");

for(int x=0;x<arr.length;x++){

System.out.print(arr[x]);

}

System.out.println("]");

}

注意:當捕獲到的異常,本功能處理不了時,可以繼續在catch中拋出,讓調用者去處理。

public static void method(){

try{

異常代碼;

}

catch(MyException e){

throw new MyException("MyException");

}

}


/* 
畢老師用電腦上課。 
  
問題領域中涉及兩個對象。 
畢老師,電腦。 
  
分析其中的問題。 
  
比如電腦藍屏啦。冒煙啦。 
  
*/  

/*

對電腦藍屏故障進行描述

*/

importjava.util.Random;
class LanPingException extendsException  {  

LanPingException(String msg)  {  

super(msg);  

}  

}

/*

對電腦冒煙故障進行描述

*/


class MaoYanException extends Exception  {  

MaoYanException(String msg)  {  

super(msg);  

}  

}   

/*

對課程出現問題進行描述

*/


class NoPlanException extends Exception  {  

NoPlanException(String msg)  {  

super(msg);  

}  

}  

/*

對電腦進行描述

一個是電腦的運行方法 run()

一個是電腦的重啓方法 reset()

*/


class Computer  {  

private int state = new Random().nextInt(3);  

public void run() throws LanPingException,MaoYanException{  

if(state==1)  

throw new LanPingException("電腦藍屏啦!!");  

if(state==2)  

throw new MaoYanException("電腦冒煙啦!!");  

System.out.println("電腦運行");  

}  

public void reset()  

state= 0;  

System.out.println("電腦重啓");  

}  

/*

對教師進行描述

教師屬性 姓名(name),電腦(comp)

教師行爲 講課(prelect()) 如果出現異常,教師還可以佈置練習方法(Test())

*/
class Teacher  {  

private String name;  

private Computer comp;  

Teacher(String name)  {  

this.name= name;  

comp = new Computer();  

}  

public void prelect() throws NoPlanException  {  

try{  

comp.run();  

System.out.println(name+"老師講課");  

}  

catch(LanPingException e)  {  

System.out.println(e.toString());  

comp.reset();  

prelect();  

}  

catch(MaoYanException e)  {  

System.out.println(e.toString());  

test();  

/*

對異常進行了轉換,本人是電腦冒煙故障,但是會影響到教師的課程,所以又對異常進行了封裝,把電腦的問題轉換成教材課程無法繼續的問題,這就是異常的異常轉換。

*/

throw new NoPlanException("課時進度無法完成,原因:"+e.getMessage());  

}  

public void test()  {  

System.out.println("大家練習");  

}  

/*

創建教師對象,調用教師的講課方法。

教師講課可能出現問題,所以對發生的問題進行了處理

*/
class ExceptionTest  {  

public static void main(String[] args)  {  

Teacher t  = new Teacher("畢老師");  

try  {  

t.prelect();  

}  

catch(NoPlanException e)  {  

System.out.println(e.toString());  

System.out.println("換人或者放假");  

}  

}  

異常轉換:

如果該異常處理不了,但並不屬於該功能出現的異常,可以將異常轉換後,再拋出和該功能相關的異常

或者異常可以在內部處理,但需要將異常纏上本功能相關的內容提供出去,調用者知道,並處理,也可以將捕獲的異常處理後,轉換爲新的異常。

/*今天就到這裏了,明天對異常的代碼進行具體的補充,明天的博客會寫到多線程這一塊,甚至集合,就這樣先睡覺了*/

異常——練習

/*

有一個圓形和長方形,

都可以獲取面積,對於面積如果出現非法的數值,視爲是獲取面積出現問題

問題通過異常通過異常來表示

現有對這個程序進行基本設計

*/


/*

由於面向對象的分析,分析出對圓和長方形求出對應的面積。

由於都是求面積,所以把它們的共性向上抽取,抽成一個接口;

方便讓程序員們一看就知道這個體系是在求面積。

*/

interface Shape{

/*

分析返回結果,爲了求面積,我們只要知道面積,需不需要給我返回結果。

單純需要知道面積,而不需要面積再去做運算,是不需要返回結果的。void

*/

void getArea();

}

class NoValueRuntimeException implements RuntimeException{

NoValueException(String msg){

this.msg=msg;

}

}

class Circle implements Shape{

private double radius; 

private static final double PI = 3.14;

Circle(double radius)

if(radius <=0)

throw new NoValueRuntimeException("圓出先非法值");

this.radius=radius;

}

/*

複寫父接口的方法,定義子接口,特定內容。父類接口方法的默認權限就是public

*/

public void getArea(){

//圓形的面積計算公式:π*r2

System.out.println(PI*radius*radius);

}

}

class Rec implements Shape{

private double len;

private double wid;

Rec(double len,double wid){

if(len<=0 || wid<=0)

throw new NoValueRuntimeException("正方形出先非法值");

this.len=len;

this.wid=wid;

}

public void getArea(){

//長方形的面積計算公式:len(長)*wid(寬)

System.out.println(len*wid);

}

}

注意一點:我也是今天才想起來的,就是但寫的程序編譯的時候報異常了,那麼只要把異常處理掉,就可以了。

發佈了43 篇原創文章 · 獲贊 24 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章