internal java compiler error_Java異常處理總結

? ? ? ? ? ? 背景? ? ? ? ? ? ??

6bf81cab0e37760fd99b2705e0195efd.png

最近專門負責團隊的項目質量。我在治理異常日志過程中,總結了一下Java的異常處理。上面是我整理的最近自己比較常見的異常知識地圖。

? 異常知識地圖概述??

從異常知識地圖最左邊的根開始看,地圖從左到右的連線連接的類之間有實實在在的父子關系,在java里通過繼承來實現(除了非RuntimeException是個虛擬父節點)。

☆Java所有異常的父類是Throwable,它又分為Error和Exception。

☆?Error是程序判定如果執行了XX邏輯,則應該是至少JVM層面出現了問題。正常情況下不應該發生的。

☆?Exception意思是環境沒有什么問題,出現Exception請開發人員自己搞定。

☆?Exception分為RuntimeException運行時異常和非運行時異常。

說到這里,我們從另外一個維度給異常分類。Java異常又分為檢查異常和非檢查異常。Error和RuntimeException以及RuntimeException的子類是非檢查異常。其他是檢查異常。這個很好區分。在寫Java代碼的時候,編譯器提示需要try catch或者throws的就是檢查異常。其他是非檢查異常。后面在具體代碼實現里有體現。

☆?異常分為檢查異常和非檢查異常。? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ?典型異常發生場景? ?

典型異常發生的場景我做了一些demo,上傳到了github,地址:

https://github.com/xiexiaojing/yuna

為了方面展示使用一個統一的切面來截獲異常:

@RestControllerAdvicepublic class ControllerThrowableAdvice {    @ExceptionHandler(Throwable.class)    public String handleThrowable(Throwable e) {        return "ControllerThrowableAdvice消息:" + e.toString();    }}
ErrorError及其子類一般不是用來捕獲的,而用來拋出的。因為Error的發生意味著環境有問題,該停下來檢修了。所以一般的處理是一旦發生Error,會停止JVM。也就是平時看到的程序起不來。如下java.awt.image.Kernel的源碼。

Error除了手工拋出,在常用的類庫中不用黑科技是不能穩定復現的。所以我測試類是這么寫的

@GetMapping("/errorThrowable")public String showErrorThrowable(){ Error error = new Error("人工拋出一個Error"); throw error;}

直接訪問頁面的結果

4db7912254722bee6661ced8f6c85af3.png

ControllerThrowableAdvice消息:?

org.springframework.web.util.NestedServletException:Handler dispatch failed; nested exception is java.lang.Error: 人工拋出一個Error

上面錯誤消息意思是spring mvc通過其核心邏輯DispatcherServlet沒有找到任何一個可以處理這個返回model的,因為直接返回就是一個Error。最后顯示的消息通過ControllerThrowableAdvice進行展示。

注意Error是非檢查異常,不用顯示處理。

NPE

NPE也就是平時說的空指針異常,它非常常見,很多類都沒有對null做支持。直到apache提供了common包專門來處理這種情況。防不勝防,時不時項目還是需要為了處理這個異常上線個bugfix。

@GetMapping("/npe")public String showNullPointerException() { new HashSet<String>(null); return prefix + "異常未拋出";}

直接訪問頁面的結果

ControllerThrowableAdvice消息:java.lang.NullPointerException

這是因為new HashSet的時候傳入null。程序走不到return就拋出異常了。最后顯示的消息通過ControllerThrowableAdvice進行展示。

注意NullPointerException是非檢查異常,不用顯示處理。

算數異常

算數異常非常常見,比如做除0,會拋出異常java.lang.ArithmeticException: / by zero,提示我們該找數學老師幫我們檢查作業了。值得注意的是如果使用BigDecimal.divide來做除法,請直接使用divide(BigDecimal divisor, int scale, RoundingMode roundingMode)這個傳3個參數的,避免

divide(BigDecimal divisor)這個傳1個參數的,因為如果傳的值除不盡會拋出java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.?帶三個參數的方法會在除不盡的時候按照傳入的攝入模式和保留小數點后的位數對數據做處理。

注意ArithmeticException是非檢查異常,不用顯示處理。

未聲明異常

未聲明異常代碼量稍大,想知道測試源碼的直接去我github里下載。地址:https://github.com/xiexiaojing/yuna拋出異常的原理是使用動態代理時,如果被代理的類拋出了一個異常。但是卻沒有throws聲明。代理類找不到匹配的異常類型會拋出InvocationTargetException。從知識地圖上可以看到它是非檢查異常。最后會被UndeclaredThrowableException來處理。這是java動態代理不優雅的處理方式。建議喜歡看源碼、模仿源碼的朋友對這一點不要借鑒哦。重點來看一下運行拋出異常的打印堆棧
java.lang.reflect.UndeclaredThrowableException  at com.sun.proxy.$Proxy17.showException(Unknown Source)  at com.brmayi.yuna.controller.ExceptionController.showUndeclaredThrowableException(ExceptionController.java:62)  at com.brmayi.yuna.controller.IndexControllerTest.showUndeclaredThrowableException(IndexControllerTest.java:34)  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)  at java.lang.reflect.Method.invoke(Method.java:498)  at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)  at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)  at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)  at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)  at org.mockito.internal.runners.DefaultInternalRunner$1$1.evaluate(DefaultInternalRunner.java:44)  at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)  at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)  at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)  at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)  at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)  at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)  at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)  at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)  at org.junit.runners.ParentRunner.run(ParentRunner.java:363)  at org.mockito.internal.runners.DefaultInternalRunner$1.run(DefaultInternalRunner.java:74)  at org.mockito.internal.runners.DefaultInternalRunner.run(DefaultInternalRunner.java:80)  at org.mockito.internal.runners.StrictRunner.run(StrictRunner.java:39)  at org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.java:163)  at org.junit.runner.JUnitCore.run(JUnitCore.java:137)  at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:119)  at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)  at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)  at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)  at java.lang.reflect.Method.invoke(Method.java:498)  at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)Caused by: java.lang.reflect.InvocationTargetException  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)  at java.lang.reflect.Method.invoke(Method.java:498)  at com.brmayi.yuna.util.ObjProxy.invoke(ObjProxy.java:14)  ... 35 moreCaused by: java.lang.ArithmeticException: / by zero  at com.brmayi.yuna.service.ShowUndeclaredThrowableExceptionService.showException(ShowUndeclaredThrowableExceptionService.java:5)  ... 40 more
從打印的堆棧可以看到這個是最終的ArithmeticException拋出時被InvocationTargetException捕獲。將原來的參數傳給了InvocationTargetException后繼續拋出,最后被UndeclaredThrowableException捕獲。注意UndeclaredThrowableException是非檢查異常,不用顯示處理。不合法參數異常不合法參數異常是很多類或者方法自己定義了java基本規則外的一些規則,不滿足會拋出的異常。比如java動態代理的源碼里就寫了被代理的接口不能超過65535個。否則就拋不合法參數異常。

ca803bb51445eb47912531fa6c9bcec1.png

注意IllegalArgumentException是非檢查異常,不用顯示處理。

以上都說的是非檢查異常。下面開始檢查異常。由于IO異常很常見好構造,我們直接來看它的子類。套接字異常套接字異常在通信編程時非常常見。比如如下代碼
 @GetMapping("/socket")public String showSocketException() throws Exception {    ServerSocket socket = new ServerSocket(8081);    socket.close();    socket.setReuseAddress(true);    return prefix + "異常未拋出";}

啟動了一個套接口服務端,馬上關閉。關閉后才去調用setReuseAddress。這時候就會拋出java.net.SocketException: Socket is closed。

注意SocketException是檢查異常,需要顯示處理。

綁定異常????套接字異常有一種情況,可以明確的知道是綁定異常,就不用拋出套接字異常這樣模糊的異常了。
@GetMapping("/binding")public String showBindingException() throws Exception {    ServerSocket socket = new ServerSocket(80);    socket.setReuseAddress(true);    return prefix + "異常未拋出";}

如上,80端口是http默認端口,不能在自定義通信程序里使用。這時候就會拋出java.net.BindException: Permission denied。

注意BindException是檢查異常,需要顯示處理。

主機名未知異常

主機名未知異常在比如內網DNS出現問題、或者遠程調用時由于機器下線等原因找不到主機時出現。可以人為連接一個未啟用的端口來構造。

@GetMapping("/unknownHost")public String showUnknownHostException() throws Exception {    new Socket("ttt", 5300);    return prefix + "異常未拋出";}
注意UnknownHostException是檢查異常,需要顯示處理。超時異常

超時異常因為在分布式系統中涉及程序內部線程間、程序之間的通信多,所以非常常見。具體代碼有點長,詳見

https://github.com/xiexiaojing/yuna

拋出java.util.concurrent.TimeoutException。它是concurrent包里的一個類。

注意TimeoutException是檢查異常,需要顯示處理。

反射操作異常及其子類

反射操作異常一般只在啟動時看到,線上程序運行中一般不會發生。因為常見類里它是這么處理的

0f9376149c9f99051fd1dd112592de50.png

上面可以看到在java.net.InetAddress的源碼里,ReflectiveOperationException的處理是直接拋出Error。在程序啟動時,經常會由于maven pom里引入的包沖突、版本不合適、或者是缺少包引起「類找不到異常」。例如下面的測試例子:
@GetMapping("/classNotFound")public String showClassNotFoundException() throws Exception {    Class.forName("com.XXX");    return prefix + "異常未拋出";}

由于com.XXX不存在。會直接拋出java.lang.ClassNotFoundException: com.XXX。它是反射操作異常的子類。平時反射操作異常及它的子類異常一旦發生就會拋出Error,JVM停止。如下面的源碼:

8a600fe9bf17fff2e1528435d5140c7c.png

Spring對于異常的處理

默認異常處理

Spring的MVC在默認情況下對不能處理的異常如404、500會拋出白頁。像下面這樣:

371f240f2dd91aa66f651ab7f89c3a59.png

這是因為Spring MVC的核心處理類DispatcherServlet的doDispatch方法包含代碼片段:
mappedHandler = getHandler(processedRequest);// 找到合適的請求處理器if (mappedHandler == null || mappedHandler.getHandler() == null) {    // 原則上如果沒有找到則會進入到這里,并且設置response的狀態碼為404    // 但是經過調試并沒有進入到這里    noHandlerFound(processedRequest, response);    return;}

它最終處理是返回/error頁。也就是白頁。不知道大家有沒有注意到我前面在介紹Error的時候,定義了error頁面的url地址為errorThrowable。

42e3a0b2849d2aec8a99abdd00e1ecd0.png

這是因為error是被Spring自身占用了。如果定義為error,我們將看不到預期的結果,而是下面的白頁

fb90864c533862b7f47821e07a1bbe07.png

這里因為/error是默認頁面,返回了999的http錯誤碼,意思是請求被拒絕。自定義異常處理

在典型異常的發生場景里一開始就介紹了定義了一個統一錯誤處理如下:

@RestControllerAdvicepublic class ControllerThrowableAdvice {    @ExceptionHandler(Throwable.class)    public String handleThrowable(Throwable e) {        return "ControllerThrowableAdvice消息:" + e.toString();    }}

這是使用了spring aop做了統一攔截。Advice在AOP的概念中翻譯成增強。包括Before、After、Around等增強時機。這里類名用到了Advice意思是在controller發生Throwable時做的增強。看到有的項目喜歡用

@ExceptionHandler(Exception.class)

這個也OK。但是我會假設Everything fails! 程序在發生平時不會遇到的問題時也可控。

??? ? ? ? ? ? 總結??? ? ? ? ? ???

本文先圍繞著異常知識地圖介紹了各種異常及出現場景,最后結合Spring論述了在實際工作中如何統一處理異常。這里推薦一個學習方法:梳理知識地圖,給地圖框架填充內容,讓自己的知識體系化。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/538925.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/538925.shtml
英文地址,請注明出處:http://en.pswp.cn/news/538925.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

java異步刷新集合,同步和異步集合的性能測試,異步集合性能測試,package cn.o

同步和異步集合的性能測試&#xff0c;異步集合性能測試,package cn.opackage cn.outofmemory.snippets.core;import java.util.ArrayList;import java.util.Collections;import java.util.List;import java.util.Vector;import java.util.concurrent.TimeUnit;public class Co…

cuda nvcc版本不一致_windows 驗證CUDA和CUDNN是否安裝成功

安裝完成CUDA&#xff0c;使用 nvcc -V 驗證是否安裝成功&#xff0c;看到如下信息說明安裝成功接下來就可以安裝 cuDNN 了。安裝cuDNN下載 cuDNN&#xff0c;下載之前需要先注冊一下 Nvidia 的賬號&#xff0c;下載地址為&#xff1a;https://developer.nvidia.com/rdp/cudnn-…

Nova Cell

Nova Cell V2 詳解 現在 &#xff0c;OpenStack 在控制平面上的性能瓶頸主要在 Message Queue 和 Database 。 尤其是 Message Queue , 隨著計算節點的增加 &#xff0c; 性能變的越來越差 。 為了應對這種情況 &#xff0c; Nova 很早之前提出來 nova-cell ( 以下以 cellv1 代…

Android 通過WIFI狀態監聽廣播,判斷進入指定wifi范圍

原文地址&#xff1a;http://blog.csdn.net/kongxiuqi/article/details/52524500 --------------------------------------------- WIFI狀態變化會發送廣播&#xff0c;一些可用的廣播在WifiManger.java中可以看到。 廣播一&#xff1a;WIFI 狀態開關變化的監聽&#xff0c;en…

2018年度最佳網頁設計與開發教程

任何一個網站從開發到最終上線&#xff0c; 都是需要團隊協作且謹慎的一個過程&#xff0c;而實際中往往會遇到各類問題&#xff0c;所以網頁設計師通常需要扮演多種角色&#xff0c;除了掌握必備的網頁設計技能外&#xff0c;更應該對后期的開發流程及內容有所了解&#xff0c…

mysql_ping()函數的作用以及返回值的類型正確的是,[單選] mysql_ping()函數的作用以及返回值的類型正確的是:()...

[單選] mysql_ping()函數的作用以及返回值的類型正確的是&#xff1a;()更多相關問題中華田園犬&#xff0c;雄性&#xff0c;2歲&#xff0c;昨晚外出未歸&#xff0c;今晨發現患犬精神沉郁&#xff0c;呼吸急促&#xff0c;體溫39℃&#xff0c;左胸側壁中下部有創1884年新疆…

java 截取byte數組_2020年的秋招已經開始了!最新Java面試題大全(文末附參考答案)送給大家...

包含的模塊本文分為十九個模塊&#xff0c;分別是&#xff1a;Java 基礎、容器、多線程、反射、對象拷貝、Java Web 、異常、網絡、設計模式、Spring/Spring MVC、Spring Boot/Spring Cloud、Hibernate、MyBatis、RabbitMQ、Kafka、Zookeeper、MySQL、Redis、JVM共包含 208 道面…

MVP模式在Android項目中的使用

煩了在Activity中編寫太多的代碼&#xff0c;該app由我來主導。就選擇用MVP模式。 概述 MVP是模型&#xff08;Model&#xff09;、視圖&#xff08;View&#xff09;、主持人&#xff08;Presenter&#xff09;的縮寫&#xff0c;分別代表項目中3個不同的模塊。 模型&#…

運行時錯誤7內存溢出_C++程序運行時的內存模型

C程序在運行時會將內存劃分為4個區域&#xff1a;1代碼區&#xff1a;存放函數體的二進制代碼&#xff0c;由操作系統進行管理2全局區&#xff1a;存放程序的全局變量、靜態變量、常量3棧區&#xff1a;由編譯器進行自動分配和釋放&#xff0c;存放函數的參數值&#xff0c;局部…

php strip_tags 少,詳解PHP函數 strip_tags的用法不足之處

這篇文章主要介紹了詳解PHP函數 strip_tags 處理字符串缺陷bug的相關資料,需要的朋友可以參考下詳解PHP函數 strip_tags 處理字符串缺陷bugPHP 函數 strip_tags() 是一個常用函數&#xff0c;該函數可以剝去字符串中的 HTML、XML 以及 PHP 的標簽。極大方便了對字符串的操作&am…

玩轉Android之MVVM開發模式實戰,炫酷的DataBinding!

原文&#xff1a;http://blog.csdn.net/u012702547/article/details/52077515 --------------------------------------------------------- MVP可以結合android的DataBinding -------------------------以下轉載--------------- C# 很早就有了MVVM的開發模式&#xff0c;An…

打造一款便攜版的Sublime Text

https://segmentfault.com/a/1190000000707661 https://www.cnblogs.com/52cik/p/sublime-diy.html 直接安裝Sublime Text&#xff0c;不要打開 大家可以參照上文提到的《Sublime Text 全程指引》中的步驟去進行安裝。我這里使用的是Sublime Text 2&#xff0c;其實3也是一樣的…

confluence創建頁面加載緩慢_樹莓派4B使用docker安裝confluence

說明confluence是一個專業的企業知識管理與協同軟件&#xff0c;可以用于構建企業wiki。通過它可以實現團隊成員之間的協作和知識共享。現在大多數公司都會部署一套confluence&#xff0c;用作內部wiki。另外confluence也可以作為個人的知識管理工具來用&#xff0c;只需要花10…

python用map提取一個數的個十百位數_如何使用python中的map函數?

我們在使用python過程中&#xff0c;為了避免錯誤刪除&#xff0c;會選擇做好一個序列后可以插入另外的序列中做為新序列的一部分內容。方便完成一些復雜的工程或多個片段分別編輯后再串成一個完整工程的操作。之前小編向大家介紹了在序列中起到累計作用的reduce函數(https://w…

matlab粒子加速器仿真,粒子群算法優化PID參數 仿真不出結果 程序如下

用的是《MATLAB智能算法30個案例分析》中的程序1.文件名為PSO_PID.mfunction z PSO_PID(x)assignin(base,Kp,x(1)); % 粒子群依次賦值給Kp 這部分運行結果> PSO_PIDassignin(base,Ki,x(2)); …

CentOS5、6的啟動流程

CentOS5/6的啟動流程啟動流程畫了張圖,看著更清晰些: (centos7的啟動流程變化挺大的,這部分待補充)補充(/etc/rc.d/rc.local 不屬于任何服務,為特殊文件,可將不能定義為服務又想開機運行的命令定義在此文件中)添加自定義服務:[rootel5 init.d]# vi /etc/init.d/testsrv #!/bin…

Spark交互式分析平臺Apache Zeppelin的安裝

Zeppelin介紹 Apache Zeppelin提供了web版的類似ipython的notebook&#xff0c;用于做數據分析和可視化。背后可以接入不同的數據處理引擎&#xff0c;包括Spark, Hive, tajo等&#xff0c;原生支持Scala, Java, shell, markdown等。它的整體展現和使用形式和Databricks Cloud是…

win7 php zend,win7系統打開WZend Studio PHP出錯的解決方法

很多朋友安裝win7系統后&#xff0c;在使用的過程中會遇到win7系統打開WZend Studio PHP出錯的情況&#xff0c;可能有很多用戶還是不能自己處理win7系統打開WZend Studio PHP出錯的問題&#xff0c;其實簡單的來說處理win7系統打開WZend Studio PHP出錯的問題只需要按照 1、在…

9個元素換6次達到排序序列_C語言必學的12個排序算法:希爾排序(第3篇)

基本思想希爾排序&#xff08;Shells Sort&#xff09;&#xff0c;以發明人命名&#xff0c;又稱為縮小增量排序&#xff0c;也是一種插入排序算法。主要思想&#xff1a;直接插入排序算法時間和待排數據有關&#xff0c;其平均復雜度是O(n^2)&#xff0c;但是在待排數據已經有…

java快捷鍵禁用_pycharm 掌握這些快捷鍵,你就是大神!!

最重要的快捷鍵1. ctrlshiftA:萬能命令行 2. shift兩次:查看資源文件新建工程第一步操作1. module設置把空包分層去掉,compact empty middle package 2. 設置當前的工程是utf-8,設置的Editor-->File Encodings-->全部改成utf-8,注釋1. ctrl/:單行注釋光標操作1. ctrlalte…