錯誤是我們?nèi)松斜夭豢缮俚囊环N美侵贵,是的朴皆,同時是很讓人不爽的娩怎。而在java程序中也會出現(xiàn)這樣或那樣不爽的問題搔课。如果程序中存在錯誤,或者由于一些外部等不良情況發(fā)生了截亦,這就會使得用戶的數(shù)據(jù)受損爬泥。所以,一個好的程序崩瓤,應(yīng)該盡量避免此類情況的發(fā)生袍啡,或者必須“治愈這種病”,也就是對程序的異常進(jìn)行處理谷遂。所以應(yīng)該做到這樣幾點(diǎn):
1葬馋、將可能發(fā)生的錯誤通知給用戶
2、發(fā)生錯誤的時候肾扰,應(yīng)該講已操作的數(shù)據(jù)進(jìn)行保存其結(jié)果
3畴嘶、提供給用戶適當(dāng)?shù)耐緩浇Y(jié)束程序。
4集晚、程序員還需定期查看程序異常窗悯,并進(jìn)行修正
一、異常概述:
1偷拔、異常是指程序在運(yùn)行時出現(xiàn)的不正常情況
2蒋院、異常由來:問題是現(xiàn)實(shí)生活中的事物亏钩,也可以通過java類的形式進(jìn)行描述,并封裝成對象欺旧。因?yàn)楫惓R部梢员怀槿」贸螅纬梢粋€體系,并由一個個具體的實(shí)例組成辞友,也是一個個對象栅哀。
3、程序可能出現(xiàn)的錯誤或問題
a.用戶輸入錯誤導(dǎo)致的異常:如用戶不正常使用程序称龙,輸入一些非法參數(shù)
b.設(shè)備硬件等發(fā)生的錯誤:如硬盤損壞等
c.物理限制:如存儲空間不足等
d.代碼錯誤:在程序編寫的方法可能不正確留拾,返回錯誤參數(shù)等。
二鲫尊、異常體系:
1痴柔、異常分為兩種:嚴(yán)重的和非嚴(yán)重的異常。
a.嚴(yán)重的異常:java通過Error類進(jìn)行描述疫向;一般不編寫針對性的代碼進(jìn)行處理
b.非嚴(yán)重異常:java通過Exception類進(jìn)行描述咳蔚,可使用針對性的代碼對其處理
共性:
a.都含有不正常情況的信息,引發(fā)原因等
b.都是通過抽取形成了超類Throwable
·RuntimeException:由程序錯誤導(dǎo)致的異常鸿捧。
·IOException:程序本身沒問題屹篓,由I/O錯誤導(dǎo)致的異常。
規(guī)則:
若出現(xiàn)RuntimeException異常匙奴,一定是自己的問題堆巧。
2、Exception中異常劃分:
1)編譯時被檢測異常(編譯javac時會檢查代碼):該異常在編譯時泼菌,若未處理(沒有拋也沒有try)谍肤,編譯失敗,該異常被標(biāo)識哗伯,代表可被處理荒揣。
2)運(yùn)行時異常(編譯時不檢查)-RuntimeException:編譯時,無需處理焊刹,編譯器不檢查該異常發(fā)生系任,建議不處理,讓程序停止虐块,需對代碼進(jìn)行修正俩滥。
RuntimeException:若在函數(shù)內(nèi)拋出該異常,函數(shù)上可不用聲明贺奠,也可通過霜旧,若在函數(shù)上聲明了該異常,調(diào)用者可不用進(jìn)行處理儡率,編譯也可通過挂据。
可不在函數(shù)上聲明以清,因?yàn)闊o需讓調(diào)用者處理。當(dāng)異常發(fā)生時崎逃,希望程序停止掷倔,因?yàn)樵谶\(yùn)行時,出現(xiàn)了無法繼續(xù)運(yùn)算的情況婚脱,希望停止程序后今魔,對代碼進(jìn)行修正。
3障贸、繼承的異常簡介:
1)繼承于RuntimeException的異常情況:
·錯誤類型轉(zhuǎn)換:ClassCastException
·空指針異常:NullPointerException
·數(shù)組訪問越界:IndexOutOfBoundsException
2)非繼承于RuntimeException的異常情況:
·試圖在文件尾部讀取數(shù)據(jù)
·試圖打開一個錯誤格式的URL
·試圖根據(jù)給定的字符串查找class對象,而此字符串表示的類不存在
三吟宦、異常的處理:
異常處理的任務(wù):將控制權(quán)從錯誤產(chǎn)生的地方轉(zhuǎn)移給能處理錯誤這種情況的錯誤處理器篮洁。
若函數(shù)上聲明了異常,調(diào)用者需進(jìn)行處理殃姓,處理方法可以throw袁波,可以try。
1蜗侈、對捕獲的異常對象進(jìn)行常見方法的操作:
trrows Exception:拋出異常
try-catch-finally:捕獲異常 ---- java中提供了特有的語句進(jìn)行處理篷牌。
String getMessage();獲得異常信息
2、throw和throws的用法:
1)throw:定義在函數(shù)內(nèi)踏幻,用于拋出異常對象枷颊。注:throw單獨(dú)存在時,下面不要定義語句该面,因?yàn)閳?zhí)行不到夭苗,編譯失敗。
2)throws:定義在函數(shù)上隔缀,用于跑出異常類题造,可拋多個,用逗號隔開猾瘸。
注:當(dāng)函數(shù)內(nèi)有throw拋出異常對象界赔,必須給出對應(yīng)的處理動作,若并未進(jìn)行try處理牵触,需在函數(shù)上聲明淮悼,否則編譯失敗。
一般函數(shù)出現(xiàn)異常荒吏,需在函數(shù)上聲明敛惊,但RuntimeException除外,若在函數(shù)內(nèi)拋出此異常绰更,函數(shù)上可不聲明瞧挤。
3锡宋、異常處理語句:
結(jié)合方式:
① try-chatch ②try-finally ③try-catch-finally
格式:
try
{
//需要被檢測的代碼;
}
catch (異常類 變量)
{
//理異常的代碼;(處理方式)
}
finally
{
//一定會執(zhí)行的語句;
}
在函數(shù)上聲明異常:便于提高安全性,讓調(diào)用者進(jìn)行處理特恬,若不處理执俩,則編譯失敗
注:finally中定義的通常為:關(guān)閉資源代碼,因?yàn)橘Y源必須被釋放癌刽。
有一種情況不會執(zhí)行finally役首,即出現(xiàn)System.exit(0);這條語句,后面的finally不會執(zhí)行显拜,因?yàn)檫@個代表系統(tǒng)退出嗎衡奥,JVM結(jié)束。
try {
...
} catch () {
//......
System.exit(0);
} finally {
...
}
4远荠、多異常的處理:
1)聲明異常時矮固,建議聲明更為具體的異常,這樣處理更具體譬淳。
注:拋出幾個具體的問題處理時档址,就具體處理哪些問題,而不是再加上catch(Exception e){...}讓JVM自己將問題解決后再繼續(xù)運(yùn)行邻梆,那么調(diào)用者將不知道發(fā)生了什么問題守伸。
2)原則:
對方聲明幾個異常,就對應(yīng)幾個catch塊浦妄,不要定義多余catch尼摹,若多個catch塊中的異常出現(xiàn)繼承關(guān)系,父類異常catch塊校辩,放最下面(最大窘问,處理更多)。
3)建議:
在進(jìn)行catch處理時宜咒,catch中一定要定義具體處理方式惠赫,不要簡單的定義一句:e.printStatckTrace();,也不要簡單的打印一句故黑。
遇到異常要怎么處理呢儿咱?常規(guī)做法是不打印異常信息,因?yàn)榧磿r打印了场晶,用戶也無法解決掉混埠,最好是將問題或信息記錄下來,并存儲為異常日志文件诗轻,便于程序員管理查閱钳宪,并及時修正代碼,管理程序。
四吏颖、自定義異常:
1搔体、概述:
因?yàn)轫?xiàng)目中會出現(xiàn)特有問題,而這些問題并未被java所描述并封裝成對象半醉,所以這些特有問題可按java中對問題封裝的思想疚俱,將特有問題進(jìn)行定義的異常封裝。
2缩多、繼承Exception或RuntimeException的原因:
1)異常體系有一個特點(diǎn):異常類和異常對象都被拋出呆奕,他們都具有可拋性。這個可拋性是Throwable這個體系單獨(dú)有的特點(diǎn)衬吆,只有此體系中的類和對象才可被throws和throw操作梁钾。
2)為了讓該類具備操作異常的共性方法。
3逊抡、定義異常信息:
由于父類中把異常信息的操作完成了陈轿,所以子類只需要在構(gòu)造函數(shù)時,將異常信息傳遞給父類秦忿,通過super語句,則可直接用getMessage方法蛾娶,自動自定義的異常灯谣。
class MyException extends Exception
{
MyException(String message)
{
super(message);
....
}
}
自定義異常時,若該異常的發(fā)生無法繼續(xù)進(jìn)行運(yùn)算蛔琅,就讓自定義異常繼承RuntimeException胎许。
五、異常的好處:
1罗售、將問題進(jìn)行封裝
2辜窑、將正常流程代碼和問題處理代碼相分離,便于閱讀寨躁。
六穆碎、異常處理原則
1、處理方式:throw或throws
2职恳、調(diào)用到拋出異常的功能時所禀,拋幾個,處理幾個放钦,一個try可以對應(yīng)多個catch
3色徘、多個catch,父類catch放在最下面操禀。
4褂策、catch內(nèi)需要定義針對性的處理方式,不要定義printStackTrace,輸出語句也不要不寫斤寂,當(dāng)捕獲到異常耿焊,本功能處理不了時,可繼續(xù)在catch中拋出
若該異常處理不了扬蕊,但不屬于該功能出現(xiàn)的異常搀别,可以講異常轉(zhuǎn)換后,再拋出或可處理異常尾抑,但需要將異常產(chǎn)生的和本功能相關(guān)的問題提供出去歇父,讓調(diào)用者知道并處理,也可以將捕獲的異常處理后轉(zhuǎn)換為新異常再愈。如匯款的例子榜苫。
示例:
try
{
throw new AException();
}
catch (AException e)
{
//方式一
throw e;
//方式二
...處理AException語句
throw new BException();
}
七、異常注意事項(xiàng):
1翎冲、在子父類覆蓋時:
1)子類拋出的異常須為父類異常的子類或子集
2)若父類或接口無異常拋出垂睬,子類覆蓋的方法出現(xiàn)異常,只能try抗悍,不能拋驹饺。
2、異常機(jī)制:
1)只有在異常情況下使用異常缴渊,不可隨處都用
2)不能過分的細(xì)化異常赏壹,即將正常程序和錯誤處理分開。這樣也更清晰衔沼。
3)充分使用異常體系結(jié)構(gòu):Exception的體系很龐大蝌借,不要拋出由于邏輯錯誤造成的異常,要將一種異常轉(zhuǎn)換成另一種更加適合的異常時指蚁,就需要拋出新異常菩佑,讓可處理此異常的調(diào)用者處理。
4)不要壓制異常:java中存在著強(qiáng)烈關(guān)閉異常的傾向凝化。即使很難出現(xiàn)異常情況時稍坯,也要考慮異常的發(fā)生,并聲明后將其關(guān)閉缘圈。
5)在檢查錯誤時劣光,要對異常“苛刻”一些糟把,異常越是具體越好绢涡,將異常的范圍縮小處理(或拋出)。
6)不要保留異常遣疯,要敢于傳遞異常:傳遞異常比捕獲異常更好雄可,讓高層次的方法通告用戶發(fā)生的錯誤凿傅,或者放棄不成功的命令更加合適。
原則:對于異常:早拋出数苫,晚捕獲聪舒。
參考例子:
/*
畢老師用電腦講課
開始思考上課中出現(xiàn)的問題:如:電腦藍(lán)屏、電腦冒煙
描述問題虐急,封裝成對象
可當(dāng)冒煙發(fā)生后箱残,出現(xiàn)講課無法繼續(xù)。
出現(xiàn)了講師的問題:課程計(jì)劃無法完成
*/
//自定義藍(lán)屏異常
class LanPingException extends Exception {
LanPingException(String messgae)
{
super(messgae);
}
}
//自定義冒煙異常
class MaoYanException extends Exception
{
MaoYanException(String messgae)
{
super(messgae);
}
}
//自定義課時無法繼續(xù)異常
class NoPlanExceptioon extends Exception
{
NoPlanExceptioon(String messgae)
{
super(messgae);
}
}
class Computer
{
//state為1時止吁,正常被辑;為2時,藍(lán)屏敬惦;為3時盼理,冒煙
private int state = 3;
public void run()throws LanPingException,MaoYanException
{
if (state ==2)
throw new LanPingException("藍(lán)屏了");
if (state ==3)
throw new MaoYanException("冒煙了");
System.out.println("run");
}
//重啟,恢復(fù)藍(lán)屏異常
public void reset()
{
state = 1;
System.out.println("reset");
}
}
//創(chuàng)建教師類
class Teacher
{
private String name;
Computer comp;//講課要用電腦俄删,初始化老師時就產(chǎn)生這個
Teacher(String name)
{
this.name = name;
comp = new Computer();
}
//定義上課方法
public void prelect()throws NoPlanExceptioon//冒煙了就不要拋MaoYanException了宏怔,因?yàn)檫@個異常老師解決不了,直接拋出老師熟悉的異常
{
try
{
comp.run();
}
catch (LanPingException l)
{
comp.reset();
}
catch (MaoYanException m)//注意這里
{
test();
throw new NoPlanExceptioon("課時無法繼續(xù)" + m.getMessage());//再次拋出異常畴椰,拋給熟悉該異常的人
}
System.out.println("講課");
}
public void test()
{
System.out.println("練習(xí)");
}
}
//測試
class ExceptionTest
{
public static void main(String[] args)
{
Teacher t = new Teacher("畢老師");
try
{
t.prelect();
}
catch (NoPlanExceptioon n)
{
System.out.println(n.toString());
System.out.println("換老師或放假");
}
}
}
/*
有個圓形和長方形臊诊,都可以獲取面積,對于面積若出現(xiàn)非法數(shù)值斜脂,是為獲取面積出問題
問題通過異常來表示
*/
//創(chuàng)建輸入值錯誤的異常
class NoValueException extends RuntimeException//對問題名稱的描述妨猩,更具體
{
NoValueException(String message)
{
super(message);
}
}
//創(chuàng)建接口,抽取獲取面積方法
interface ShapeArea
{
void getArea();
}
//創(chuàng)建獲取長方形面積的類
class Rec implements ShapeArea
{
private int len,wid;
//此處聲明了秽褒,就會將問題拋給主函數(shù)中解決
Rec(int len,int wid)throws NoValueException
{
if (len<=0 || wid<=0)
throw new NoValueException("出現(xiàn)非法值了");
this.len = len;
this.wid = wid;
}
public void getArea()
{
System.out.println(len*wid);
}
}
//創(chuàng)建獲取圓形面積的類
class Circle implements ShapeArea
{
private int rad;
private static final double PI = 3.14;
//此處未聲明,當(dāng)調(diào)用該函數(shù)威兜,發(fā)生異常時會直接結(jié)束程序销斟,并打印具體的異常信息
Circle(int rad)
{
if (rad<=0)
throw new NoValueException("出現(xiàn)非法值了");
this.rad = rad;
}
public void getArea()
{
System.out.println(rad*rad*PI);
}
}
//測試
class Exception
{
public static void main(String[] args)
{
//方式一:出現(xiàn)異常時,信息不具體
try
{
Rec r= new Rec(-3,4);
r.getArea();
}
catch (NoValueException e)
{
System.out.println(e.toString());
}
System.out.println("OVER");
//方式二:出現(xiàn)異常時椒舵,信息更具體
Circle c = new Circle(-8);
c.getArea();
}
}