日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

internal java compiler error_Java异常处理总结

發(fā)布時間:2025/3/11 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 internal java compiler error_Java异常处理总结 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

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

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

? 異常知識地圖概述??

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

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

☆?Error是程序判定如果執(zhí)行了XX邏輯,則應(yīng)該是至少JVM層面出現(xiàn)了問題。正常情況下不應(yīng)該發(fā)生的。

☆?Exception意思是環(huán)境沒有什么問題,出現(xiàn)Exception請開發(fā)人員自己搞定。

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

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

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

? ?典型異常發(fā)生場景? ?

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

https://github.com/xiexiaojing/yuna

為了方面展示使用一個統(tǒng)一的切面來截獲異常:

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

Error除了手工拋出,在常用的類庫中不用黑科技是不能穩(wěn)定復(fù)現(xiàn)的。所以我測試類是這么寫的

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

直接訪問頁面的結(jié)果

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 + "異常未拋出";}

直接訪問頁面的結(jié)果

ControllerThrowableAdvice消息:java.lang.NullPointerException

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

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

算數(shù)異常

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

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

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

未聲明異常

未聲明異常代碼量稍大,想知道測試源碼的直接去我github里下載。地址:https://github.com/xiexiaojing/yuna拋出異常的原理是使用動態(tài)代理時,如果被代理的類拋出了一個異常。但是卻沒有throws聲明。代理類找不到匹配的異常類型會拋出InvocationTargetException。從知識地圖上可以看到它是非檢查異常。最后會被UndeclaredThrowableException來處理。這是java動態(tài)代理不優(yōu)雅的處理方式。建議喜歡看源碼、模仿源碼的朋友對這一點不要借鑒哦。重點來看一下運行拋出異常的打印堆棧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捕獲。將原來的參數(shù)傳給了InvocationTargetException后繼續(xù)拋出,最后被UndeclaredThrowableException捕獲。注意UndeclaredThrowableException是非檢查異常,不用顯示處理。不合法參數(shù)異常不合法參數(shù)異常是很多類或者方法自己定義了java基本規(guī)則外的一些規(guī)則,不滿足會拋出的異常。比如java動態(tài)代理的源碼里就寫了被代理的接口不能超過65535個。否則就拋不合法參數(shù)異常。

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

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

啟動了一個套接口服務(wù)端,馬上關(guān)閉。關(guān)閉后才去調(diào)用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是檢查異常,需要顯示處理。

主機名未知異常

主機名未知異常在比如內(nèi)網(wǎng)DNS出現(xiàn)問題、或者遠程調(diào)用時由于機器下線等原因找不到主機時出現(xiàn)。可以人為連接一個未啟用的端口來構(gòu)造。

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

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

https://github.com/xiexiaojing/yuna

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

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

反射操作異常及其子類

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

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

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

Spring對于異常的處理

默認異常處理

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

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

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

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

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

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

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

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

@ExceptionHandler(Exception.class)

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

??? ? ? ? ? ? 總結(jié)??? ? ? ? ? ???

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

總結(jié)

以上是生活随笔為你收集整理的internal java compiler error_Java异常处理总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。