您好,登錄后才能下訂單哦!
這篇文章主要介紹“2021最新版java異常面試題有哪些”,在日常操作中,相信很多人在2021最新版java異常面試題有哪些問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”2021最新版java異常面試題有哪些”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
Java異常是Java提供的一種識別及響應錯誤的一致性機制。 Java異常機制可以使程序中異常處理代碼和正常業務代碼分離,保證程序代碼更加優雅,并提高程序健壯性。在有效使用異常的情況下,異常能清晰的回答what, where, why這3個問題:異常類型回答了“什么”被拋出,異常堆棧跟蹤回答了“在哪”拋出,異常信息回答了“為什么”會拋出。
1. Throwable
Throwable 是 Java 語言中所有錯誤與異常的超類。
Throwable 包含兩個子類:Error(錯誤)和 Exception(異常),它們通常用于指示發生了異常情況。
Throwable 包含了其線程創建時線程執行堆棧的快照,它提供了 printStackTrace() 等接口用于獲取堆棧跟蹤數據等信息。
2. Error(錯誤)
定義:Error 類及其子類。程序中無法處理的錯誤,表示運行應用程序中出現了嚴重的錯誤。
特點:此類錯誤一般表示代碼運行時 JVM 出現問題。通常有 Virtual MachineError(虛擬機運行錯誤)、NoClassDefFoundError(類定義錯誤)等。比如 OutOfMemoryError:內存不足錯誤;StackOverflflowError:棧溢出錯誤。此類錯誤發生時,JVM 將終止線程。這些錯誤是不受檢異常,非代碼性錯誤。因此,當此類錯誤發生時,應用程序不應該去處理此類錯誤。按照Java慣例,我們是不應該實現任何新的Error子類的!
3. Exception(異常)
程序本身可以捕獲并且可以處理的異常。Exception 這種異常又分為兩類:運行時異常和編譯時異常。
運行時異常
定義:RuntimeException 類及其子類,表示 JVM 在運行期間可能出現的異常。
特點:Java 編譯器不會檢查它。也就是說,當程序中可能出現這類異常時,倘若既"沒有通過throws聲明拋出它",也"沒有用try-catch語句捕獲它",還是會編譯通過。比如NullPointerException空指針異常、ArrayIndexOutBoundException數組下標越界異常、ClassCastException類型轉換異常、ArithmeticExecption算術異常。此類異常屬于不受檢異常,一般是由程序邏輯錯誤引起的,在程序中可以選擇捕獲處理,也可以不處理。雖然 Java 編譯器不會檢查運行時異常,但是我們也可以通過 throws 進行聲明拋出,也可以通過 try-catch 對它進行捕獲處理。如果產生運行時異常,則需要通過修改代碼來進行避免。例如,若會發生除數為零的情況,則需要通過代碼避免該情況的發生!
RuntimeException 異常會由 Java 虛擬機自動拋出并自動捕獲(就算我們沒寫異常捕獲語句運行時也會拋出錯誤!!),此類異常的出現絕大數情況是代碼本身有問題應該從邏輯上去解決并改進代碼。
編譯時異常
定義: Exception 中除 RuntimeException 及其子類之外的異常。
特點: Java 編譯器會檢查它。如果程序中出現此類異常,比如 ClassNotFoundException(沒有找到指定的類異常),IOException(IO流異常),要么通過throws進行聲明拋出,要么通過trycatch進行捕獲處理,否則不能通過編譯。在程序中,通常不會自定義該類異常,而是直接使用系 統提供的異常類。該異常我們必須手動在代碼里添加捕獲語句來處理該異常。
4. 受檢異常與非受檢異常
Java 的所有異常可以分為受檢異常(checked exception)和非受檢異常(uncheckedexception)。
受檢異常
編譯器要求必須處理的異常。正確的程序在運行過程中,經常容易出現的、符合預期的異常情況。一旦發生此類異常,就必須采用某種方式進行處理。除 RuntimeException 及其子類外,其他的Exception 異常都屬于受檢異常。編譯器會檢查此類異常,也就是說當編譯器檢查到應用中的某 處可能會此類異常時,將會提示你處理本異常——要么使用try-catch捕獲,要么使用方法簽名中用 throws 關鍵字拋出,否則編譯不通過。
非受檢異常
編譯器不會進行檢查并且不要求必須處理的異常,也就說當程序中出現此類異常時,即使我們沒有try-catch捕獲它,也沒有使用throws拋出該異常,編譯也會正常通過。該類異常包括運行時異常(RuntimeException極其子類)和錯誤(Error)。
try – 用于監聽。將要被監聽的代碼(可能拋出異常的代碼)放在try語句塊之內,當try語句塊內發生異常時,異常就被拋出。
catch – 用于捕獲異常。catch用來捕獲try語句塊中發生的異常。
fifinally – fifinally語句塊總是會被執行。它主要用于回收在try塊里打開的物力資源(如數據庫連接、網絡連接和磁盤文件)。只有fifinally塊,執行完成之后,才會回來執行try或者catch塊中的return或者throw語句,如果fifinally中使用了return或者throw等終止方法的語句,則就不會跳回執行,直接停止。
throw – 用于拋出異常。
throws – 用在方法簽名中,用于聲明該方法可能拋出的異常。
通常,應該捕獲那些知道如何處理的異常,將不知道如何處理的異常繼續傳遞下去。傳遞異常可以在方法簽名處使用 throws 關鍵字聲明可能會拋出的異常。
注意
非檢查異常(Error、RuntimeException 或它們的子類)不可使用 throws 關鍵字來聲明要拋出的異常。
一個方法出現編譯時異常,就需要 try-catch/ throws 處理,否則會導致編譯錯誤。
如果你覺得解決不了某些異常問題,且不需要調用者處理,那么你可以拋出異常。
throw關鍵字作用是在方法內部拋出一個 Throwable 類型的異常。任何Java代碼都可以通過throw語句拋出異常。
程序通常在運行之前不報錯,但是運行后可能會出現某些未知的錯誤,但是還不想直接拋出到上一級,那么就需要通過try…catch…的形式進行異常捕獲,之后根據不同的異常情況來進行相應的處理。
可以根據下圖來選擇是捕獲異常,聲明異常還是拋出異常
直接拋出異常
通常,應該捕獲那些知道如何處理的異常,將不知道如何處理的異常繼續傳遞下去。傳遞異常可以在方法簽名處使用 throws 關鍵字聲明可能會拋出的異常。
private static void readFile(String filePath) throws IOException { File file = new File(filePath); String result; BufferedReader reader = new BufferedReader(new FileReader(file)); while((result = reader.readLine())!=null) { System.out.println(result); } reader.close(); }
封裝異常再拋出
有時我們會從 catch 中拋出一個異常,目的是為了改變異常的類型。多用于在多系統集成時,當某個子系統故障,異常類型可能有多種,可以用統一的異常類型向外暴露,不需暴露太多內部異常細節。
private static void readFile(String filePath) throws MyException { try { // code } catch (IOException e) { MyException ex = new MyException("read file failed."); ex.initCause(e); throw ex; } }
捕獲異常
在一個 try-catch 語句塊中可以捕獲多個異常類型,并對不同類型的異常做出不同的處理
private static void readFile(String filePath) { try { // code } catch (FileNotFoundException e) { // handle FileNotFoundException } catch (IOException e){ // handle IOException } }
同一個 catch 也可以捕獲多種類型異常,用 | 隔開
private static void readFile(String filePath) { try { // code } catch (FileNotFoundException | UnknownHostException e) { // handle FileNotFoundException or UnknownHostException } catch (IOException e){ // handle IOException } }
自定義異常
習慣上,定義一個異常類應包含兩個構造函數,一個無參構造函數和一個帶有詳細描述信息的構造函數(Throwable 的 toString 方法會打印這些詳細信息,調試時很有用)
public class MyException extends Exception { public MyException(){ } public MyException(String msg){ super(msg); } // ... }
try-catch-fifinally
當方法中發生異常,異常處之后的代碼不會再執行,如果之前獲取了一些本地資源需要釋放,則需要在方法正常結束時和 catch 語句中都調用釋放本地資源的代碼,顯得代碼比較繁瑣,fifinally 語句可以解決這個問題。
private static void readFile(String filePath) throws MyException { File file = new File(filePath); String result; BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(file)); while((result = reader.readLine())!=null) { System.out.println(result); } } catch (IOException e) { System.out.println("readFile method catch block."); MyException ex = new MyException("read file failed."); ex.initCause(e); throw ex; } finally { System.out.println("readFile method finally block."); if (null != reader) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } }
調用該方法時,讀取文件時若發生異常,代碼會進入 catch 代碼塊,之后進入 fifinally 代碼塊;若讀取文件時未發生異常,則會跳過 catch 代碼塊直接進入 fifinally 代碼塊。所以無論代碼中是否發生異常,fifianlly 中的代碼都會執行。
若 catch 代碼塊中包含 return 語句,fifinally 中的代碼還會執行嗎?將以上代碼中的 catch 子句修改如下:
catch (IOException e) { System.out.println("readFile method catch block."); return; }
調用 readFile 方法,觀察當 catch 子句中調用 return 語句時,fifinally 子句是否執行
readFile method catch block. readFile method finally block.
可見,即使 catch 中包含了 return 語句,fifinally 子句依然會執行。若 fifinally 中也包含 return 語句,fifinally 中的 return 會覆蓋前面的 return.
try-with-resource
上面例子中,fifinally 中的 close 方法也可能拋出 IOException, 從而覆蓋了原始異常。JAVA 7 提供了更優雅的方式來實現資源的自動釋放,自動釋放的資源需要是實現了 AutoCloseable 接口的類。
private static void tryWithResourceTest(){ try (Scanner scanner = new Scanner(new FileInputStream("c:/abc"),"UTF-8")){ // code } catch (IOException e){ // handle exception } }
try 代碼塊退出時,會自動調用 scanner.close 方法,和把 scanner.close 方法放在 fifinally 代碼塊中不同的是,若 scanner.close 拋出異常,則會被抑制,拋出的仍然為原始異常。被抑制的異常會由 addSusppressed 方法添加到原來的異常,如果想要獲取被抑制的異常列表,可以調用getSuppressed 方法來獲取。
Error 類型的錯誤通常為虛擬機相關錯誤,如系統崩潰,內存不足,堆棧溢出等,編譯器不會對這類錯誤進行檢測,JAVA 應用程序也不應對這類錯誤進行捕獲,一旦這類錯誤發生,通常應用程序會被終止,僅靠應用程序本身無法恢復;
Exception 類的錯誤是可以在應用程序中進行捕獲并處理的,通常遇到這種錯誤,應對其進行處理,使應用程序可以繼續正常運行。
運行時異常包括 RuntimeException 類及其子類,表示 JVM 在運行期間可能出現的異常。 Java 編譯器不會檢查運行時異常。
受檢異常是Exception 中除 RuntimeException 及其子類之外的異常。 Java 編譯器會檢查受檢異常。
RuntimeException異常和受檢異常之間的區別:是否強制要求調用者必須處理此異常,如果強制要求調用者必須進行處理,那么就使用受檢異常,否則就選擇非受檢異常(RuntimeException)。一般來講,如果沒有特殊的要求,我們建議使用RuntimeException異常。
在一個方法中如果發生異常,這個方法會創建一個異常對象,并轉交給 JVM,該異常對象包含異 常名稱,異常描述以及異常發生時應用程序的狀態。創建異常對象并轉交給 JVM 的過程稱為拋出異常。可能有一系列的方法調用,最終才進入拋出異常的方法,這一系列方法調用的有序列表叫做調用棧。
JVM 會順著調用棧去查找看是否有可以處理異常的代碼,如果有,則調用異常處理代碼。當 JVM發現可以處理異常的代時,會把發生的異常傳遞給它。如果 JVM 沒有找到可以處理該異常的代碼塊,JVM 就會將該異常轉交給默認的異常處理器(默認處理器為 JVM 的一部分),默認異常處理器打印出異常信息并終止應用程序。
Java 中的異常處理除了包括捕獲異常和處理異常之外,還包括聲明異常和拋出異常,可以通過throws 關鍵字在方法上聲明該方法要拋出的異常,或者在方法內部通過 throw 拋出異常對象。
throws 關鍵字和 throw 關鍵字在使用上的幾點區別如下:
throw 關鍵字用在方法內部,只能用于拋出一種異常,用來拋出方法或代碼塊中的異常,受查異常和非受查異常都可以被拋出。
throws 關鍵字用在方法聲明上,可以拋出多個異常,用來標識該方法可能拋出的異常列表。一個方法用 throws 標識了可能拋出的異常列表,調用該方法的方法中必須包含可處理異常的代碼,否則也要在方法簽名中用 throws 關鍵字聲明相應的異常。
fifinal可以修飾類、變量、方法,修飾類表示該類不能被繼承、修飾方法表示該方法不能被重寫、修飾變量表示該變量是一個常量不能被重新賦值。
fifinally一般作用在try-catch代碼塊中,在處理異常的時候,通常我們將一定要執行的代碼方法fifinally代碼塊中,表示不管是否出現異常,該代碼塊都會執行,一般用來存放一些關閉資源的代碼。
fifinalize是一個方法,屬于Object類的一個方法,而Object類是所有類的父類,Java 中允許使用fifinalize()方法在垃圾收集器將對象從內存中清除出去之前做必要的清理工作。
NoClassDefFoundError 是一個 Error 類型的異常,是由 JVM 引起的,不應該嘗試捕獲這個異常。
引起該異常的原因是 JVM 或 ClassLoader 嘗試加載某類時在內存中找不到該類的定義,該動作發生在運行期間,即編譯時該類存在,但是在運行時卻找不到了,可能是變異后被刪除了等原因導致;
ClassNotFoundException 是一個受查異常,需要顯式地使用 try-catch 對其進行捕獲和處理,或在方法簽名中用 throws 關鍵字進行聲明。當使用 Class.forName, ClassLoader.loadClass 或ClassLoader.fifindSystemClass 動態加載類到內存的時候,通過傳入的類路徑參數沒有找到該類,就會拋出該異常;另一種拋出該異常的可能原因是某個類已經由一個類加載器加載至內存中,另一個加載器又嘗試去加載它。
ClassCastException(類轉換異常)
IndexOutOfBoundsException(數組越界)
NullPointerException(空指針)
ArrayStoreException(數據存儲異常,操作數組時類型不一致)
還有IO操作的BufffferOverflflowException異常
java.lang.IllegalAccessError:違法訪問錯誤。當一個應用試圖訪問、修改某個類的域(Field)或者調用其方法,但是又違反域或方法的可見性聲明,則拋出該異常。
java.lang.InstantiationError:實例化錯誤。當一個應用試圖通過Java的new操作符構造一個抽象類或者接口時拋出該異常.
java.lang.OutOfMemoryError:內存不足錯誤。當可用內存不足以讓Java虛擬機分配給一個對象時拋出該錯誤。
java.lang.StackOverflflowError:堆棧溢出錯誤。當一個應用遞歸調用的層次太深而導致堆棧溢出或者陷入死循環時拋出該錯誤。
java.lang.ClassCastException:類造型異常。假設有類A和B(A不是B的父類或子類),O是A的實例,那么當強制將O構造為類B的實例時拋出該異常。該異常經常被稱為強制類型轉換異常。
java.lang.ClassNotFoundException:找不到類異常。當應用試圖根據字符串形式的類名構造類,而在遍歷CLASSPAH之后找不到對應名稱的class文件時,拋出該異常。
java.lang.ArithmeticException:算術條件異常。譬如:整數除零等。
java.lang.ArrayIndexOutOfBoundsException:數組索引越界異常。當對數組的索引值為負數或大于等于數組大小時拋出。
java.lang.IndexOutOfBoundsException:索引越界異常。當訪問某個序列的索引值小于0或大于等于序列大小時,拋出該異常。
java.lang.InstantiationException:實例化異常。當試圖通過newInstance()方法創建某個類的實例,而該類是一個抽象類或接口時,拋出該異常。
java.lang.NoSuchFieldException:屬性不存在異常。當訪問某個類的不存在的屬性時拋出該異常。
java.lang.NoSuchMethodException:方法不存在異常。當訪問某個類的不存在的方法時拋出該異常。-
java.lang.NullPointerException:空指針異常。當應用試圖在要求使用對象的地方使用了null時,
拋出該異常。譬如:調用null對象的實例方法、訪問null對象的屬性、計算null對象的長度、使用throw語句拋出null等等。
java.lang.NumberFormatException:數字格式異常。當試圖將一個String轉換為指定的數字類型,而該字符串確不滿足數字類型要求的格式時,拋出該異常。
java.lang.StringIndexOutOfBoundsException:字符串索引越界異常。當使用索引值訪問某個字符串中的字符,而該索引值小于0或大于等于序列大小時,拋出該異常。
不應該使用異常控制應用的執行流程,例如,本應該使用if語句進行條件判斷的情況下,你卻使用異常處理,這是非常不好的習慣,會嚴重影響應用的性能。
如果使用內建的異常可以解決問題,就不要定義自己的異常。Java API 提供了上百種針對不同情況的異常類型,在開發中首先盡可能使用 Java API 提供的異常,如果標準的異常不能滿足你的要求,這時候創建自己的定制異常。盡可能得使用標準異常有利于新加入的開發者看懂項目代碼。
綜上所述,當你拋出或捕獲異常的時候,有很多不同的情況需要考慮,而且大部分事情都是為了改善代碼的可讀性或者 API 的可用性。
異常不僅僅是一個錯誤控制機制,也是一個通信媒介。因此,為了和同事更好的合作,一個團隊必須要制定出一個最佳實踐和規則,只有這樣,團隊成員才能理解這些通用概念,同時在工作中使用它。
到此,關于“2021最新版java異常面試題有哪些”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。