java try catch 例子_java try catch
try catch機制非常好。那些覺得try catch不行的人,是他們自己的水平有問題,無法理解這種機制。并且這群人寫代碼不遵守規則,喜歡偷懶,這才造成try catch不好的錯覺。
詳細解釋:
1.程序要健壯,必須要設計報錯機制。
最古老,也是最常見的,比如:
bool CreateFile( );
//如果創建文件失敗就返回false,否則返回true。
這種報錯方式,顯然不好。因為它沒有給出產生錯誤的具體原因。
2.改進:一個函數或過程,會因為不同的原因產生錯誤,報錯機制必須要把這些錯誤原因進行區分后,再匯報。
比如:
int CreateFile():
//如果創建成功就返回1.
//如果是因為沒有權限,導致失敗,返回-1。
//如果是因為文件已經存在,導致失敗,返回-2。
//如果是因為創建文件發生超時,導致失敗,返回-3。
這樣看上去,比【1】要好些,至少指出了比較具體的失敗原因,但是,還不夠。
3.很多情況下,函數需要把詳細的原因,用字符串的方式,返回:
class Result
{
....int State;//同【2】
....string ErrorMessage;//如果失敗,這里將給出詳細的信息,如果有可能,應該把建議也寫上去。
}
Result CreateFile();
//如果創建成功,返回的Result,State為1,ErrorMessage為null。
//如果是因為沒有權限,導致失敗,返回的Result,State為-1,ErrorMessage為"用戶【guest】沒有權限在【C:\】這個目錄下創建該文件。建議您向管理員申請權限,或者更換具有權限的用戶。"。
//如果是因為文件已經存在,導致失敗,返回的Result,State為-2,ErrorMessage為"文件【C:\abc.txt】已經存在。如果需要覆蓋,請添加參數:arg_overwrite = true"。
//如果是因為創建文件發生超時,導致失敗,返回的Result,State為-3,ErrorMessage為"在創建文件時超時,請使用chkdsk檢查文件系統是否存在問題。"。
4.我個人推崇上面這種方式,完整,美觀。但是這種流程,容易與正常的代碼混在一起,不好區分開。因此,Java、C#等設計了try catch這一種特殊的方式:
void CreateFile()
//如果創建成功就不會拋出異常。
//如果是因為沒有權限,導致失敗,會拋出AccessException,這個Exception的Msg屬性為"用戶【guest】沒有權限在【C:\】這個目錄下創建該文件。建議您向管理員申請權限,或者更換具有權限的用戶。"。
//如果是因為文件已經存在,導致失敗,會拋出FileExistedException,這個Exception的Msg屬性為"文件【C:\abc.txt】已經存在。如果需要覆蓋,請添加參數:arg_overwrite = true"。
//如果是因為創建文件發生超時,導致失敗,會拋出TimeoutException,這個Exception的Msg屬性為"在創建文件時超時,請使用chkdsk檢查文件系統是否存在問題。"。
可見,上述機制,實際上是用不同的Exception代替了【3】的State。
這種機制,在外層使用時:
try
{
....CreateFile( "C:\abc.txt" );
}
catch( AccessException e )
{
....//代碼進入這里說明發生【沒有權限錯誤】
}
catch( FileExistedException e )
{
....//代碼進入這里說明發生【文件已經存在錯誤】
}
catch( TimeoutException e )
{
....//代碼進入這里說明發生【超時錯誤】
}
對比一下【3】,其實這與【3】本質相同,只是寫法不同而已。
5.綜上,我個人喜歡【3】這類面向過程的寫法。但很多喜歡面向對象的朋友,估計更喜歡【4】的寫法。然而【3】與【4】都一樣。這兩種機制都是優秀的錯誤處理機制。
6.理論說完了,回到正題,題注問:為什么不用try catch?
答:這是因為,很多菜鳥,以及新手,他們是這樣寫代碼的:
void CreateFile( )
//無論遇到什么錯誤,就拋一個 Exception,并且也不給出Msg信息。
這樣的話,在外層只能使用:
try
{
....CreateFile( "C:\abc.txt" );
}
catch( Exception e )
{
....//代碼進入這里說明發生錯誤
}
當出錯后,只知道它出錯了,并不知道是什么原因導致錯誤。這同【1】。
以及,即使CreateFile是按【4】的規則設計的,但菜鳥在外層是這樣使用的:
try
{
....CreateFile( "C:\abc.txt" );
}
catch( Exception e )
{
....//代碼進入這里說明發生錯誤
....throw Exception( "發生錯誤" )
}
這種情況下,如果這位菜鳥的同事,調用了這段代碼,或者用戶看到這個錯誤信息,也只能知道發生了錯誤,但并不清楚錯誤的原因。這與【1】是相同的。
出于這些原因,菜鳥的同事,以及用戶,并沒有想到,造成這個問題是原因菜鳥的水平太差,寫代碼圖簡單省事。他們卻以為是try catch機制不行。
因此,這就導致了二逼同事,以及傻比用戶,不建議用try catch。
通常try/catch適用于以下場景:
在代碼中對可預見而又無法掌控的情況進行處理。比如在SOCKET BIND時發現端口已經被占用了、或者IO在打開文件時發現文件不存在,就需要在catch中做適當的處理避免程序crash掉;
將問題向更上一層面傳遞,將處理權讓渡給caller。假如你寫了個ORM FRAMEWORK,在delete的時候發現外鍵關聯刪除失敗,FRAMEWORK不能擅自替上層的代碼決定該怎么辦,于是只好把DB的報的錯誤原樣(或者加層外衣)throw出來,調用者根據業務需要選擇處理方式;
除此之外,所有問題應該由程序員主動判斷,就地解決。在規模比較大的軟件中,定義自己的Exception體系并正確、克制地使用try/catch,可以讓代碼變得易讀易維護還美觀。
傳遞給上層來解決例子如下:
void handlearray(int a[]) throws Npe
{
if(a==null)
throw new Npe();
a[0]……//處理部分
}
上層:
try{
handlearray(a);
}catch(E… e)
{
//對a進行處理。
}
這時候傳入數組為空,這個錯誤不是你當前這個函數所能處理的,只能是拋給上層,也就是生成這個數組,或者能對這個數組負責的那部分代碼,讓上層去處理,上層去try cacth,并在catch中對異常處理,類庫中類似的像文件io的時候很多讀寫類都會拋出FileNotFoundException,也是一個道理,當上層給我一個找不到的文件,那在我的io類中肯定無法處理你這個異常,只能拋到給我這個文件的那一層,讓那一層的代碼對這個問題進行反應。
當然有些時候不需要,比如:
void makearray(int a[])
{
a=new int[];
……//生成部分
if(a==null)
……//處理部分,此處一般不用拋異常,直接可以在這一層處理掉。
}
像這個就不一樣了,因為這次發生的問題是在我這一層代碼所能控制之內的,所以我直接把問題處理掉就好了,沒必要給上層了。
為什么講“正確”并“克制”地使用?因為有些又蠢又懶的程序員喜歡這么干:
將函數所有代碼都放到try{}之中,哪怕 int i = 1這種賦值的都不放過。然后在catch里輸出一個錯誤信息就萬事大吉。這樣看起來是很省心哇,不用動腦子去分析哪里可能發生什么錯誤,反正所有錯誤都在catch的掌控之中;
用try/catch來控制流程。舉個簡單的例子,假設有這么個要求:
將字符串轉換成數字,并返回該數字的絕對值,如果出錯了就返回-1. 于是乎,就能見到類似下面代碼的奇葩做法:
int parse_number(const char* s){
try{
return abs(atoi(s));
}catch(Exception){
return -1;
}
}
這多省事兒,不用考慮s是不是NULL、不用考慮s是不是包含非數字的字符、不用考慮s是不是超出int的取值范圍...我是個優秀的程序員耶~~,我的代碼好簡潔。
try/catch和errno可以結合起來使用,二者不是非此即彼的關系,比如在某些場景下,可以將不確定的錯誤簡化歸納為固定的errno輸出,調用者直接檢查返回的errno即可,簡化了代碼,也減輕了負擔。比如某函數,成功返回0,失敗返回-1:
int foo(double d){
try{
do_something(d);
return 0;
}catch(Exception){
return -1;
}
}
void bar(double d){
int result = foo(d);
if(result == -1) return;
do_next_steps();
}
三、細節
Java中try,catch,finally的用法
Java異常處理的組合方式:
1.try+catch
運行流程:運行到try塊中,如果有異常拋出,則轉到catch塊去處理。然后執行catch塊后面的語句
2.try+catch+finally
運行流程:運行到try塊中,如果有異常拋出,則轉到catch塊,catch塊執行完畢后,執行finally塊的代碼,再執行finally塊后面的代碼。
如果沒有異常拋出,執行完try塊,也要去執行finally塊的代碼。然后執行finally塊后面的語句
網上有很多人探討Java中異常捕獲機制try...catch...finally塊中的finally語句是不是一定會被執行?很多人都說不是,當然他們的回答是正確的,經過我試驗,至少有兩種情況下finally語句是不會被執行的:
(1)try語句沒有被執行到,如在try語句之前就返回了,這樣finally語句就不會執行,這也說明了finally語句被執行的必要而非充分條件是:相應的try語句一定被執行到。
(2)在try塊中有System.exit(0);這樣的語句,System.exit(0);是終止Java虛擬機JVM的,連JVM都停止了,所有都結束了,當然finally語句也不會被執行到。
四、檢查型異常和非檢查型異常
Paste_Image.png
上圖摘自Java 進階 之 檢查型異常與非檢查型異常
直接繼承 Exception 的異常,屬于檢查型異常,必須用try語句塊進行處理或者把異常交給上級方法處理總之就是必須寫代碼處理它。如IOException,SQLException
繼承自Runtime Exception或 Error 的是非檢查型異常,可以不用捕獲
1、throws出現在方法函數頭;而throw出現在函數體。
2、throws表示出現異常的一種可能性,并不一定會發生這些異常;throw則是拋出了異常,執行throw則一定拋出了某種異常對象。
3、兩者都是消極處理異常的方式(這里的消極并不是說這種方式不好),只是拋出或者可能拋出異常,但是不會由函數去處理異常,真正的處理異常由函數的上層調用處理。
總結
以上是生活随笔為你收集整理的java try catch 例子_java try catch的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 觅凤c语言教程,C语言程序设计教程 第1
- 下一篇: php factory interfac