第十一章 异常,日志,断言和调试
2019獨角獸企業重金招聘Python工程師標準>>>
第十一章?異常,日志,斷言,調試
????由于程序的錯誤或一些外部環境的影響造成用戶數據的丟失,用戶就有可能不再使用這個程序了。為了避免,應該做到以下幾點:
向用戶通告錯誤
保存所有的操作結果
允許用戶以適當的形式退出程序。
11.1?處理異常
????當由于出現錯誤而使得某些操作沒有完成,程序應該:
返回到一種安全狀態,并能夠讓用戶執行一些其他命令;或者
允許用戶保存所有操作的結果,以適當的方式終止程序
????異常處理的任務就是將控制權從錯誤產生的地方轉移給能夠處理這種錯誤的處理器。程序中可能出現的錯誤和問題:
用戶輸入錯誤
設備錯誤
物理限制(磁盤滿了)
代碼錯誤,例如(方法返回一個錯誤答案,或錯誤調用其他方法;使用了一個無效的數組下標;試圖查找一個在散列表中不存在的數據項;試圖對一個空棧進行退棧。)
11.1.1?異常分類
異常對象都是派生與Throwable類的一個實例,如果java內置的異常類不能夠滿足需求,用戶還可以創建自己的異常類。
????Error類層次結構描敘了java運行時系統的內部錯誤和資源耗盡錯誤。
????在java設計是,需要關注Exception層次結構。兩個分支:
派生于RuntimeException(程序錯誤導致)
錯誤的類型轉換
數組訪問越界(通過檢查數組下標,避免ArrayIndexOutOfBoundsException)
訪問空指針(在使用變量之前檢查是否為空來杜絕NullPointerException)
包含其他異常(程序本身沒問題,像類似于I/O錯誤這類問題導致的異常)
試圖在文件尾部后讀取數據
試圖打開一個錯誤格式的URL
試圖根據給定的字符串查找Class對象,而這個字符串表示的類不存在
????如果出現RuntimeException異常,就一定是你的問題。
????異常的分類:
未檢查異常
派生于Error
派生于RuntimeException
其他異常稱為已檢查異常。
11.1.2?聲明已檢查異常
????一個方法不僅需要告訴編譯器將要返回什么值,還要告訴編譯器有可能發生什么錯誤。方法應該在其收不聲明所有可能排除的異常。這樣可以從首部反映這個方法可能拋出哪類已檢查異常。
????自己編寫方法是,不必將可能拋出的異常都進行聲明。需要記住下面四種情況應該拋出異常:
調用一個拋出已檢查異常的方法,例如FileInputStream
程序運行過程中發現錯誤,并且利用throw語句拋出一個已檢查異常
程序出現錯誤,例如a[-1] = 0?會拋出一個ArrayIndexOutOfBoundsException
java虛擬機和運行時庫出現內部異常
????如果出現前兩中情況,必須告訴調用這個方法的程序員有可能拋出異常。因為任何一個拋出異常的方法都有可能是一個死亡陷阱,如果沒有處理器捕獲這個異常,當前執行的線程就會結束。
????對于那些可能被他人使用的java方法,應該根據異常規范,在方法首部聲明這個方法可能拋出的異常。
class?MyAnimation {...public?Iamge?loadImage(String?s)?throws?IOException{...} }拋出多個已檢查異常,必須在首部列出所有的異常類,逗號隔開
class?MyAnimation {...public?Iamge?loadImage(String?s)?throws?EOFExceoption,MalformedURLException{...} }????不需要聲明java內部錯誤,即Error派生的錯誤。也不應該聲明從RuntimeException派生的那些未檢查異常。這些錯誤應該多花時間在修正程序中的錯誤上,而不是說明這些錯誤發生的可能性上。
????總之,一個方法必須聲明所有可能拋出的已檢查異常,而未檢查異常要么不可控制(Error),要么應該避免發生(RuntimeException)。
????除了聲明異常外,還可以捕獲異常。這樣會使異常不被拋到方法之外,也不需要throws規范。
????警告:如果子類中覆蓋了超類的一個方法,子類聲明的已檢查異常不能超過超類方法中什么的異常范圍。如果超類方法沒有拋出任何已檢查異常,子類也不應該拋出任何已檢查異常。
11.1.3??如何拋出異常
????對于一個已存在的異常類:
找到一個合適的異常類
創建這個類的一個對象
將對象拋出
????一旦方法拋出了異常,這個方法就不可能返回到調用者。
????例如讀一個文件首部,讀到某個字符后結束了,認為不正常,希望拋出一個異常。
????首先決定拋出什么類型異常,歸結為IOException是一種很好的選擇,仔細閱讀Java?API會發現:EOFException是在輸入過程中,遇到了一個未預期的EOF后的信號。
String?readData(Scanner?in)?throws?EOFException {...while(...){if(!in.hasNext())?//EOFException{if(n<len)throws?new?EOFException;}...}???return?s; }????EOFException類還有一個字符串型參數的構造器。
String?gripe?=?"Content-length:"+len+".?Received:?"+n; throws?new?EOFException(gripe);11.1.4?創建異常類
定義一個派生于Exception類,或其子類的類。習慣上,定義這樣的類應該包含兩個構造器,一個默認;另一個是帶有描敘信息的構造器(超類Throwable的toString方法會打印這些詳細信息,在調試中非常有用)。
class?FileFromatException?extends?IOException {public?FileFormatException(){}public?FileFormatException(String?gripe){super(gripe);} }?11.2 捕獲異常
捕獲異常用try/catch語句塊。
try {codemore?code } catch(ExceptionType?e) {handler?for?this?type }如果在try語句塊中的任何代碼拋出了一個在catch子句中說明的異常類,那么:
程序將跳過try語句塊的其余代碼
程序將執行catch子句中的處理代碼
????如果try中沒有拋出任何異常,程序將跳過catch子句。如果拋出的是catch子句中沒有聲明的異常類型,這個方法就會立刻退出。
????如果調用了一個已檢查異常的方法,就必須對它進行處理,或者將它傳遞出去。通常應該捕獲那些知道如何處理,而將那些不知道怎樣處理的異常傳遞出去(throws)。一個例外:如果編寫一個覆蓋超類的方法,而這個方法有沒有拋出異常,那么這個方法就必須捕獲方法代碼中出現的每一個已檢查異常。
11.2.1 捕獲多個異常
try
{code?that?might?throws?exceptions
}
catch(MalformedURLException?e1)
{emergency?action?for?malformed?URLs
}
catch(UnkownHostException?e2)
{emergency?action?for?unknown?hosts
}
catch(IOexception?e3)
{emergency?action?for?all?other?I/O?problems
} ????異常對象(e1,e2,e3)可能包含異常本身有關的信息。想要獲得更多信息可用
e1.getMessage()或得到異常對象的類型
e3.getClass().getName()11.2.2 再次拋出異常與異常鏈
????在catch子句中可以拋出一個異常,這樣子的目的是改變異常的類型。ServletException例子。執行servlet的代碼可能不想知道發生錯誤的細節,但希望明確知道servlet是否故障。
try {access?the?database } catch(SQLException?e) {throw?new?ServletException("database?error:?"+e.getMessage()); }????在java SE 1.4中,有一種更好的處理方法
try {access?the?database } catch(SQLException?e) {Throwable?se?=?new?ServletException("database?error:?");se.initCause(e);//重新得到原始異常throw?se; }????強烈建議這種包裝技術,可以讓用戶拋出子系統中的高級異常,而不丟失原始異常細節。如果一個方法中發生類一個已檢查異常,而不允許拋出,那包裝技術十分有用。捕獲這個已檢查異常,并將其包裝成一個運行時異常。
11.2.3 Finally子句
????如果方法獲得一些本地資源,并且只有這個方法自己知道,又如果這些資源在退出方法之前必須被回收,那么就會產生資源回收問題。finally子句解決這個問題。如果使用java編寫數據庫程序,就需要使用這個技術關閉與數據庫的連接。不管異常是否被捕獲,finally子句都會被執行。
Graphics?g?=?image.getGraphics(); try {//1code?that?might?throw?exception//2 } catch(IOException?e?) {//3show?error?dialog//4 } finally {//5g.dispose(); }??? 無論怎樣都會執行finally子句。finally子句中運用return語句會覆蓋之前的return語句。
轉載于:https://my.oschina.net/liuyang2077/blog/504639
總結
以上是生活随笔為你收集整理的第十一章 异常,日志,断言和调试的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 蓝懿教育九月八日记录
- 下一篇: 在CentOS 6.3中安装与配置JDK