什么是異常?
異常實(shí)際上是程序中錯(cuò)誤導(dǎo)致中斷了正常的指令流的一種事件.
異常處理的優(yōu)點(diǎn):
沒有處理錯(cuò)誤的程序:
?read-file {
?????openTheFile;
?????determine its size;
?????allocate that much memory;
?????closeTheFile; ?
}
以常規(guī)方法處理錯(cuò)誤
openFiles;
if (theFilesOpen) {
??determine the lenth of the file;
??if (gotTheFileLength){
????allocate that much memory;
????if (gotEnoughMemory) {
???????read the file into memory;
???????if (readFailed) errorCode=-1;
???????else errorCode=1;
????}else ?errorCode=-3;
??}else errorCode=-5 ;
?}else errorCode=-5;
觀察前面的程序你會發(fā)現(xiàn)大部分精力花在出錯(cuò)處理上了.
只把能夠想到的錯(cuò)誤考慮到,對以外的情況無法處理
程序可讀性差
出錯(cuò)返回信息量太少
用異常的形式處理錯(cuò)誤
read-File;
{ try {
????openTheFile;
????determine its size;
????allocate that much memory;
????closeTheFile;
?}catch(fileopenFailed) { dosomething; }
??catch(sizeDetermineFailed) {dosomething;}
??catch(memoryAllocateFailed){ dosomething;}
??catch(readFailed){ dosomething;}
??catch(fileCloseFailed) { dosomething; }
??catch(Exception) {dosomething;} ?//其它未考慮到的錯(cuò)誤
綜合上面的說法和傳統(tǒng)的方法比較異常的優(yōu)點(diǎn):
1.把錯(cuò)誤代碼從常規(guī)代碼中分離出來
2.把錯(cuò)誤傳播給調(diào)用堆棧
M1=>M2=>M3? M3異常 =>M2 =>M1=>...=>Main=>CLR
3. 按錯(cuò)誤類型和錯(cuò)誤差別分組
4. 系統(tǒng)提供了對于一些無法預(yù)測的錯(cuò)誤的捕獲和處理
5. 克服了傳統(tǒng)方法的錯(cuò)誤信息有限的問題
什么情況下使用例外機(jī)制?
1.當(dāng)方法因?yàn)樽陨頍o法控制的原因而不能完成其任務(wù)
???? 文件不存在聂儒,網(wǎng)絡(luò)連接無法建立……
2.處理在方法、類庫、類中拋出的例外
???? 如FileInputStream.read產(chǎn)生IOException
3.在大的項(xiàng)目中采用統(tǒng)一的方式處理例外時(shí)
???? 如編寫一個(gè)文字處理器
4.例外應(yīng)該是不經(jīng)常發(fā)生但卻可能發(fā)生的故障
???? 一定發(fā)生的事件不應(yīng)該用例外機(jī)制來處理
5.例外處理用于使系統(tǒng)從故障中恢復(fù)
???? 提示信息/不產(chǎn)生無效的結(jié)果/釋放資源
注意事項(xiàng):
1.不同的例外處理策略
???? 關(guān)鍵性應(yīng)用(處理所有例外)
???? 實(shí)驗(yàn)軟件(可以忽略許多例外)
2.終止程序會導(dǎo)致資源泄漏岖沛,利用例外處理釋放資源
3.盡可能近地處理例外辨泳,這樣程序清晰易讀
4.能在局部處理的錯(cuò)誤不要使用例外機(jī)制
???? 例外機(jī)制的處理比正常處理效率低
異常的分類:
只要在程序執(zhí)行過程中出現(xiàn)錯(cuò)誤恕出,.NET Framework 就會創(chuàng)建一個(gè) Exception 對象詳細(xì)描述此錯(cuò)誤。在 .NET Framework 中喊崖,Exception 為所有異常類的基類。
從 Exception 類派生的異常分為兩種類別:
SystemException \ ApplicationException雇逞。
一個(gè)例外是由一個(gè)對象來代表的
所有的例外都直接或間接地繼承自Exception類
注意:
用戶也可以通過繼承已有的例外類來定義自己的例外類荤懂,并在程序中使用(利用throw產(chǎn)生或拋出,catch捕捉并處理)塘砸。
一些常見的 System 異常包括:
ArgumentException:
在調(diào)用某方法時(shí)节仿,傳遞的參數(shù)中至少有一個(gè)不符合所調(diào)用方法的參數(shù)規(guī)范。
ArgumentNullException:
調(diào)用方法時(shí)所傳遞的參數(shù)中掉蔬,至少有一個(gè)在任何情況下都不應(yīng)為 null廊宪。
ArgumentOutOfRangeException:
調(diào)用方法時(shí),如果在傳遞給該方法的參數(shù)中至少有一個(gè)不為null且不包含有效值時(shí)女轿,引發(fā)該異常箭启。
ArithmeticException:操作將導(dǎo)致上溢或下溢。
ArrayTypeMismatchException:
當(dāng)試圖在數(shù)組中存儲類型不正確的元素時(shí)引發(fā)的異常蛉迹。
DivideByZeroException:
試圖用零除整數(shù)值或十進(jìn)制數(shù)值時(shí)引發(fā)的異常傅寡。
DllNotFoundException:
當(dāng)未找到在 DLL 導(dǎo)入中指定的 DLL 時(shí)所引發(fā)的異常。
IndexOutOfRangeException:
使用了大于數(shù)組或集合大小的索引。
InsufficientMemoryException:
當(dāng)檢測到?jīng)]有足夠的可用內(nèi)存時(shí)引發(fā)的異常荐操。無法繼承此類大猛。
InvalidCastException:
因無效類型轉(zhuǎn)換或顯式轉(zhuǎn)換引發(fā)的異常。
InvalidOperationException:
當(dāng)方法調(diào)用對于對象的當(dāng)前狀態(tài)無效時(shí)引發(fā)的異常淀零。
NotImplementedException:
在無法實(shí)現(xiàn)請求的方法或操作時(shí)引發(fā)的異常挽绩。
NotSupportedException:
當(dāng)調(diào)用的方法不受支持,或試圖讀取或?qū)懭氩恢С值牧鲿r(shí)引發(fā)的異常驾中。
NullReferenceException:
在將引用設(shè)置為有效實(shí)例之前使用了引用的屬性或方法唉堪。
OutOfMemoryException:
沒有足夠的內(nèi)存繼續(xù)執(zhí)行程序時(shí)引發(fā)的異常
OverflowException:
在選中的上下文中的算術(shù)運(yùn)算、類型轉(zhuǎn)換或轉(zhuǎn)換操作導(dǎo)致溢出時(shí)引發(fā)的異常肩民。
FormatException:
參數(shù)或操作數(shù)格式不正確唠亚。
捕捉異常:
捕獲并處理異常
try ?
{
??//接受監(jiān)視的程序塊,在此區(qū)域內(nèi)發(fā)生
??//的異常,由catch中指定的程序處理;
}
// 不能有其它語句分隔
catch(要處理的異常種類和標(biāo)識符)
{
??//處理異常;
}
catch(要處理的異常種類和標(biāo)識符)
{
??//處理異常;
}
try語句:異常監(jiān)視塊
作用:監(jiān)視該代碼塊是否有異常發(fā)生,若有異常持痰,產(chǎn)生異常對象并拋出
注意:在該代碼塊中聲明的變量無法在該塊之外訪問
catch語句:異常處理代碼塊
作用:捕捉try語句中拋出的異常灶搜,并按照代碼塊中的語句處理
格式:
catch(異常種類){//處理語句}
catch(異常種類 引用名(一般叫e)){//處理語句}:
注意:
1.每個(gè)try語句必須伴隨1-n個(gè)catch語句
2.例外總是由距離產(chǎn)生例外最近的匹配catch代碼段處理
3.try-catch可以嵌套使用:
如果沒有相應(yīng)的例外處理
???? 則例外被交給上一層try代碼段進(jìn)行處理
4.匹配的catch執(zhí)行完畢后,同級的catch將被忽略
5.先catch小的再catch老的
6.整個(gè)執(zhí)行流程中若無catch處理 程序中斷工窍!
7.catch的類型應(yīng)盡量精確
8.請注意你調(diào)用的方法是否有可能拋出異常
9.catch中也可能產(chǎn)生異常 會拋給嵌套的上一級處理
10.處理過的異掣盥簦可以繼續(xù)拋出 以期通知流程中的所有節(jié)點(diǎn)有異常
catch (Exception e) { throw e; }
11.try-catch機(jī)制不該被用于流程控制,例外情形應(yīng)該是很稀少的患雏,而不是經(jīng)常性的
編寫程序,包含四種異常
算術(shù)異常, 字符串越界,數(shù)組越界,格式異常(字符串轉(zhuǎn)數(shù)字)
觀察輸出信息:
每個(gè)異常對象可以直接給出信息
一定會執(zhí)行的程序塊---finally
異常處理的統(tǒng)一出口
try
{
? //常規(guī)的代碼;
}
catch()
{
//處理異常
}
finally
{
? //不論發(fā)生什么異常(或者不發(fā)生任何異常),都要執(zhí)行的部分;
}
finally:
?????1.捕獲例外的最后一步是通過finally語句為例外處理提供一個(gè)統(tǒng)一的出口鹏溯,使得在控制流程轉(zhuǎn)到程序的其他部分以前,能夠?qū)Τ绦虻臓顟B(tài)作統(tǒng)一的管理淹仑。
?????2.無論try所指定的程序塊中是否拋出例外丙挽,也無論catch語句的例外類型是否與所拋棄的例外的類型一致,finally所指定的代碼都要被執(zhí)行匀借,它提供了統(tǒng)一的出口颜阐。(finally語句與switch中的default語句是不同的!)
?????3.通常在finally語句中可以進(jìn)行資源的清除工作吓肋,如關(guān)閉打開的文件凳怨、刪除臨時(shí)文件等。
finally和return的關(guān)系:
1.當(dāng)try和catch中有return時(shí)蓬坡,finally仍然會執(zhí)行猿棉;
2.finally是在return后面的表達(dá)式運(yùn)算后執(zhí)行的(此時(shí)并沒有返回運(yùn)算后的值,而是先把要返回的值保存起來屑咳,不管finally中的代碼如何修改萨赁,返回的值都不會改變,仍然是之前保存的值)兆龙,所以函數(shù)返回值是在finally執(zhí)行前確定的杖爽;
3.finally中不可以有return敲董,否則語法錯(cuò)誤
拋出異常:
throw ExceptionObj;
拋出異常: 不是出錯(cuò)產(chǎn)生,而是人為地拋出
1.任何從Exception派生的類都可以用throw語句拋出,拋出例外用來表明程序遇到的錯(cuò)誤無法正常執(zhí)行而需要例外處理
throw new MyException(“some infomation”);
2.例外拋出點(diǎn)后的代碼在拋出例外后不再執(zhí)行
也可以說例外的拋出終止了代碼段的執(zhí)行
自定義異常:
不是由系統(tǒng)監(jiān)測到的異常(下標(biāo)越界,被0-除等),而是由用戶自己定義的異常.
形如:建議ApplicationException作為父類
class MyException : ApplicationException{….}
注意:
用戶定義的異常同樣要用try--catch捕獲,但必須由用戶自己拋出
throw new MyException(參數(shù)).
例:
計(jì)算兩個(gè)數(shù)之和,當(dāng)任意一個(gè)數(shù)超出范圍時(shí),拋出自己的異常
public class NumberRangeException : ApplicationException
{ ?
public NumberRangeException(String msg):base(msg)
{
}
}
public int CalcAnswer(String str1, String str2)
{
????int int1, int2;
????int answer = -1;
????try
????{
?????????int1 = int.Parse(str1);
?????????int2 = int.Parse(str2);
?????????if( (int1 < 10) || (int1 > 20)|| (int2 < 10) || (int2 > 20)))
?????????{
NumberRangeException e = new NumberRangeException("Numbers not within the specified range.");
????????????throw e;
?????????}
?????????answer = int1 + int2;
????}
catch (FormatException e)
{
???? ?Console.WriteLine(e);
????}
????return answer;
}
public void GetAnswer()
{
???String answerStr=null;
???try
???{
????????int answer = CalcAnswer(“12”, “5”);
???}
catch (NumberRangeException e)
{
????????answerStr = e.Message;
???}
???Console.WriteLine(answerStr);
}
1.一般格式:正常程序和出錯(cuò)處理分離開來
try
{
C# statement;
}
catch(ExceptionType1 ExceptionObject)
{
???Exception1 ?handling;
}
catch(ExceptionType2 ExceptionObject)
{
???Exception2 ?handling;
}
finally
{
???final handling;
?? // ?(統(tǒng)一的出口,最終必定要執(zhí)行)
}
2.把異常傳播給堆棧,沿著被調(diào)用的順序往前尋找,只要找到符合該異常種類徹底異常處理程序,就交給這部分程序去處理
3.異澄堪玻可以人為地拋出,用throw new 語句
5.異骋刚可以是系統(tǒng)已經(jīng)定義好的,也可以是用戶自己定義的
5.用戶自己定義的異常一定繼承自Exception類 一般繼承自ApplicationException
異常小結(jié):
1.異常是什么
2.異常怎么分類
3.異常如何捕捉 捕捉有規(guī)則嗎
4.異常在調(diào)用堆棧中怎么傳遞
5.怎么手動拋出一個(gè)異常
6.怎么自定義一個(gè)異常類