Java常見異常處理

異常是Java程序中常常遇到的問題,一個異常就是一個Bug,就要花不少時間來定位異常。
Java異常
(1)Throwable是Java異常的頂級類,全部的異常都繼承於這個類。
(2)Error,Exception是異常類的兩個大分類。
(3)Error是非程序異常,即程序不能捕獲的異常,通常是編譯或者系統性的錯誤,如OutOfMemorry內存溢出異常等。
(4)Exception是程序異常類,由程序內部產生。Exception又分爲運行時異常、非運行時異常。
(5)運行時異常的特色是Java編譯器不會檢查它,也就是說,當程序中可能出現這類異常,即便沒有用try-catch語句捕獲它,也沒有用throws子句聲明拋出它,也會編譯經過,運行時異常可處理或者不處理。運行時異常通常常出來定義系統的自定義異常,業務根據自定義異常作出不一樣的處理。常見的運行時異常如NullPointException、ArrayIndexOutOfBoundsException等。
(6)非運行時異常是程序必須進行處理的異常,捕獲或者拋出,若是不處理程序就不能編譯經過。如常見的IOException、ClassNotFoundException等。
常見的Java異常坑
最頑固的坑--NullPointerException
空指針異常應該是每個程序員必需要踩得的坑,並且應該是常常踩不斷踩的坑,極其廣泛且難以根除。可是這個坑能夠經過某些方法有效的避免。
(1)什麼是空指針?
當一個變量的值爲 null 時,在 Java 裏面表示一個不存在的空對象,沒有實際內容,沒有給它分配內存,null 也是對象成員變量的默認值。
因此,一個對象若是沒有進行初始化操做,這時候,若是你調用這個對象的方法或者變量,就會出現空指針異常。
以下面示例會發生空指針異常:
Object object = null;
String string = object.toString();
空指針它是屬於運行時異常 RuntimeException 的子類,它不是捕獲型的,只有在程序運行時纔可能報出來,並且會形成程序中斷。
如何有效避免空指針?
如下是我在編碼過程當中遇到的問題及解決辦法。
字符串比較,常量放前面---老是從已知的非空String對象中調用equals()方法
if(status.equals(SUCCESS)){
}
這個時候 status 可能爲 null 形成空指針異常,應該把常量放前面,就能避免空指針異常。這個應該在各類開發規範裏面都會提到,也是最基礎的。
if(SUCCESS.equals(status)){
}
當valueOf()和toString()返回相同的結果時,寧願使用前者。
由於調用null對象的toString()會拋出空指針異常,若是咱們可以使用valueOf()得到相同的值,那寧願使用valueOf(),傳遞一個null給valueOf()將會返回「null」,尤爲是在那些包裝類,像Integer、Float、Double和BigDecimal。
BigDecimal bd = getPrice();
System.out.println(String.valueOf(bd)); //不會拋出空指針異常
System.out.println(bd.toString()); //拋出 NullPointerException
初始化默認值
在對象初始化的時候給它一個默認值或者默認構造實現,如:
User user = new User();
String name = StringUtils.EMPTY;
避免返回空集合
在返回一個集合的話,默認會是 null,統一規範返回一個空集合。
舉個 List 例子,如:
public List getUserList(){
    List list = userMapper.gerUserList();
    return list == null ? new ArrayList() : list;
}
這樣接收方就不用擔憂空指針異常了,也不會影響業務。
採用JDK8 Optional 新特性
 Optional是Jdk8提供的一個能夠包含null值的容器對象,能夠用來代替xx != null的判斷。(這個暫時由於咱們車道系通通一適用的是Java7,這個方案尚未在車到系統代碼裏使用過。)
OutOfMemoryError
內存異常異常也是一個常常出現的Bug,可是這個不是程序能控制的,這個問題是指要分配的對象的內存超出了當前最大的堆內存,須要調整堆內存大小(-Xmx)以及優化程序。
(1)常見的有如下幾種緣由:
1.內存中加載的數據量過於龐大,如一次從數據庫取出過多數據;
2.集合類中有對對象的引用使用完後未清空,使得JVM不能回收;
3.代碼中存在死循環或循環產生過多重複的對象實體;
4.使用的第三方軟件中的BUG;
5.啓動參數內存值設定的太小
(2)常看法決方法:
1.應用服務器提示錯誤的解決:
  把啓動參數內存值設置足夠大。
2.Java代碼致使錯誤的解決:
1)檢查代碼中是否有死循環或遞歸調用。
2)檢查是否有大循環重複產生新對象實體。
3)檢查對數據庫查詢中,是否有一次得到所有數據的查詢。通常來講,若是一次取十萬條記錄到內存,就可能引發內存溢出。這個問題比較隱蔽,在上線前,數據庫中數據較少,不容易出問題,上線後,數據庫中數據多了,一次查詢就有可能引發內存溢出。所以對於數據庫查詢儘可能採用分頁的方式查詢。
4 )檢查List、MAP等集合對象是否有使用完後,未清除的問題。List、MAP等集合對象會始終存有對對象的引用,使得這些對象不能被GC回收。
IOException
IO,即:input, output,咱們在讀寫磁盤文件、網絡內容的時候常常會生的一種異常,這種異常是受檢查異常,須要進行手工捕獲。經常使用的一種異常處理方式有兩種,一種是:使用throws拋出可能發生的異常,另外一種是:直接try-catch。
ClassNotFoundException
類找不到異常,Java開發中常常遇到,是否是很絕望?這是在加載類的時候拋出來的,即在類路徑下不能加載指定的類。
注意:在車道程序中不推薦使用throws把異常拋給系統處理,車道系統要捕獲全部能捕獲的異常並進行處理,目的是當發生程序級異常時要保證車道程序能夠正常收費,不可由於程序異常影響到正在進行的收費處理。
異常處理的通常原則
一、 能處理就早處理,拋出不去還不能處理的異常就要想辦法消化掉,或者轉換爲RuntimeException處理。由於對於一個應用系統來講,拋出大量異常是有問題的,應該從程序開發角度儘量的控制異常發生的可能。
二、 對於檢查異常,若是不能行之有效的處理,還不如轉換爲RuntimeException拋出。這樣也讓上層的代碼有選擇的餘地――可處理也可不處理。
三、 對於一個應用系統來講,應該有本身的一套異常處理框架,這樣當異常發生時,也能獲得統一的處理風格,將優雅的異常信息反饋給用戶。
異常的轉譯與異常鏈 
 一、異常轉譯的原理 
所謂的異常轉譯就是將一種異常轉換另外一種新的異常,也許這種新的異常更能準確表達程序發生異常。
在Java中有個概念就是異常緣由,異常緣由致使當前拋出異常的那個異常對象,幾乎全部帶異常緣由的異常構造方法都使用Throwable類型作參數,這也就爲異常的轉譯提供了直接的支持,由於任何形式的異常和錯誤都是Throwable的子類。好比將SQLException轉換爲另一個新的異常DAOException,能夠這麼寫:
    先自定義一個異常DAOException:
   好比有一個SQLException類型的異常對象e,要轉換爲DAOException,能夠這麼寫:  
public class DAOException extends RuntimeException {
//(省略了部分代碼)
public DAOException(String message, Throwable cause) {
super(message, cause);
}
}
DAOException daoEx = new DAOException ( "SQL異常", e);
異常轉譯是針對全部繼承Throwable超類的類而言的,從編程的語法角度講,其子類之間均可以相互轉換。可是,從合理性和系統設計角度考慮,可將異常分爲三類:Error、Exception、RuntimeException。
 異常的處理存在着一套哲學思想:對於一個應用系統來講,系統所發生的任何異常或者錯誤對操做用戶來講都是系統"運行時"異常,都是這個應用系統內部的異常。這也是異常轉譯和應用系統異常框架設計的指導原則。在系統中大量處理非檢查異常的AxiTrader返傭www.fx61.com/brokerlist/axitrader.html負面影響不少,最重要的一個方面就是代碼可讀性下降,程序編寫複雜,異常處理的代碼也很蒼白無力。所以,頗有必要將這些檢查異常Exception和錯誤Error轉換爲RuntimeException異常,讓程序員根據狀況來決定是否捕獲和處理所發生的異常。
①:Error到Exception:將錯誤轉換爲異常,並繼續拋出。例如Spring WEB框架中,將org.springframework.web.servlet.DispatcherServlet的doDispatch()方法中,將捕獲的錯誤轉譯爲一個NestedServletException異常。這樣作的目的是爲了最大限度挽回因錯誤發生帶來的負面影響。由於一個Error經常是很嚴重的錯誤,可能會引發系統掛起。
②:Exception到RuntimeException:將檢查異常轉換爲RuntimeException可讓程序代碼變得更優雅,讓開發人員集中精力設計更合理的程序代碼,反過來也增長了系統發生異常的可能性。
③:Error到RuntimeException:目的仍是同樣的。把全部的異常和錯誤轉譯爲不檢查異常,這樣可讓代碼更爲簡潔,還有利於對錯誤和異常信息的統一處理。
一、 異常鏈
異常鏈顧名思義就是將異常發生的緣由一個傳一個串起來,即把底層的異常信息傳給上層,這樣逐層拋出。Java API文檔中給出了一個簡單的模型: 
try {
lowLevelOp();
} catch (LowLevelException le) {
throw (HighLevelException)
new HighLevelException().initCause(le);
}
當程序捕獲到了一個底層異常le,在處理部分選擇了繼續拋出一個更高級別的新異常給此方法的調用者。這樣異常的緣由就會逐層傳遞。這樣,位於高層的異常遞歸調用getCause()方法,就能夠遍歷各層的異常緣由。這就是Java異常鏈的原理。異常鏈的實際應用不多,發生異常時候逐層上拋不是個好注意,上層拿到這些異常又能奈之何?並且異常逐層上拋會消耗大量資源,由於要保存一個完整的異常鏈信息。html

相關文章
相關標籤/搜索