您好,登錄后才能下訂單哦!
異常是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把異常拋給系統處理,車道系統要捕獲所有能捕獲的異常并進行處理,目的是當發生程序級異常時要保證車道程序可以正常收費,不可因為程序異常影響到正在進行的收費處理。
異常處理的一般原則
1、 能處理就早處理,拋出不去還不能處理的異常就要想辦法消化掉,或者轉換為RuntimeException處理。因為對于一個應用系統來說,拋出大量異常是有問題的,應該從程序開發角度盡可能的控制異常發生的可能。
2、 對于檢查異常,如果不能行之有效的處理,還不如轉換為RuntimeException拋出。這樣也讓上層的代碼有選擇的余地――可處理也可不處理。
3、 對于一個應用系統來說,應該有自己的一套異常處理框架,這樣當異常發生時,也能得到統一的處理風格,將優雅的異常信息反饋給用戶。
異常的轉譯與異常鏈?
?1、異常轉譯的原理?
所謂的異常轉譯就是將一種異常轉換另一種新的異常,也許這種新的異常更能準確表達程序發生異常。
在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:目的還是一樣的。把所有的異常和錯誤轉譯為不檢查異常,這樣可以讓代碼更為簡潔,還有利于對錯誤和異常信息的統一處理。
1、 異常鏈
異常鏈顧名思義就是將異常發生的原因一個傳一個串起來,即把底層的異常信息傳給上層,這樣逐層拋出。Java API文檔中給出了一個簡單的模型:?
try {
lowLevelOp();
} catch (LowLevelException le) {
throw (HighLevelException)
new HighLevelException().initCause(le);
}
當程序捕獲到了一個底層異常le,在處理部分選擇了繼續拋出一個更高級別的新異常給此方法的調用者。這樣異常的原因就會逐層傳遞。這樣,位于高層的異常遞歸調用getCause()方法,就可以遍歷各層的異常原因。這就是Java異常鏈的原理。異常鏈的實際應用很少,發生異常時候逐層上拋不是個好注意,上層拿到這些異常又能奈之何?而且異常逐層上拋會消耗大量資源,因為要保存一個完整的異常鏈信息。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。