主頁 > 後端開發 > Java秋招,穩了

Java秋招,穩了

2021-09-04 07:08:15 後端開發

💂 個人主頁: Java程式魚
🤟 整個Java 體系的面試題我都會分享,大家可以持續關注
💬 如果文章對你有幫助、歡迎關注、點贊、收藏(一鍵三連)和訂閱專欄哦
💅 有任何問題歡迎私信,看到會及時回復!

序號內容鏈接地址
1Java基礎知識面試題https://blog.csdn.net/qq_35620342/article/details/119636436
2Java集合容器面試題待分享
3Java并發編程面試題待分享
4Java例外面試題https://blog.csdn.net/qq_35620342/article/details/119977051
5JVM面試題待分享
6Java Web面試題https://blog.csdn.net/qq_35620342/article/details/119642114
7Spring面試題https://blog.csdn.net/qq_35620342/article/details/119956512
8Spring MVC面試題https://blog.csdn.net/qq_35620342/article/details/119965560
9Spring Boot面試題待分享
10MyBatis面試題https://blog.csdn.net/qq_35620342/article/details/119956541
11Spring Cloud面試題待分享
12Redis面試題https://blog.csdn.net/qq_35620342/article/details/119575020
13MySQL資料庫面試題https://blog.csdn.net/qq_35620342/article/details/119930887
14RabbitMQ面試題待分享
15Dubbo面試題待分享
16Linux面試題待分享
17Tomcat面試題待分享
18ZooKeeper面試題待分享
19Netty面試題待分享
20資料結構與演算法面試題待分享

文章目錄

  • 1.Java例外架構
  • 2.Throwable
  • 3.Error(錯誤)
  • 4.Exception(例外)
  • 5.常見的非檢查性例外
  • 6.常見的檢查性例外
  • 7.Java例外關鍵字
  • 8.宣告例外
  • 9.拋出例外
  • 10.捕獲例外
  • 11.常見例外處理方式
  • 12.捕獲例外
  • 13.自定義例外
  • 14.try-catch-finally
  • 15.try-with-resource
  • 16.Error 和 Exception 區別是什么?
  • 17.Java 虛擬機是如何捕獲例外的?
  • 18. throw 和 throws 的區別是什么?
  • 19.final、finally、finalize 有什么區別?
  • 20.NoClassDefFoundError 和 ClassNotFoundException 區別?
  • 21.try-catch-finally 中哪個部分可以省略?
  • 22.try-catch-finally 中,如果 catch 中 return 了,finally 還會執行嗎?
  • 23.類 ExampleA 繼承 Exception,類 ExampleB 繼承ExampleA
  • 24.常見的 RuntimeException 有哪些?
  • 25.Java常見例外有哪些?
  • 26.在 finally 塊中清理資源或者使用 try-with-resource 陳述句
  • 27.使用 finally 代碼塊
  • 28.Java 7 的 try-with-resource 語法
  • 29.優先明確的例外
  • 30.對例外進行檔案說明
  • 31.使用描述性訊息拋出例外
  • 32.優先捕獲最具體的例外
  • 33.不要捕獲 Throwable 類
  • 34.不要忽略例外
  • 35.不要記錄并拋出例外
  • 36.包裝例外時不要拋棄原始的例外
  • 37.不要使用例外控制程式的流程
  • 38.使用標準例外
  • 39.例外會影響性能
  • 40.總結
  • 41.例外處理-阿里巴巴Java開發手冊


1.Java例外架構

在這里插入圖片描述

2.Throwable

  • Throwable 類是 Java 語言中所有錯誤或例外的超類,
  • 只有當物件是此類(或其子類之一)的實體時,才能通過 Java 虛擬機或者 Java throw 陳述句拋出,類似地,只有此類或其子類之一才可以是 catch 子句中的引數型別,
  • Throwable 包含了其執行緒創建時執行緒執行堆疊的快照,它還包含了給出有關錯誤更多資訊的訊息字串,
  • 最后,它還可以包含 cause(原因):另一個導致此 throwable 拋出的 throwable,此 cause 設施在 1.4 版本中首次出現,它也稱為例外鏈 設施,因為 cause 自身也會有 cause,依此類推,就形成了例外鏈,每個例外都是由另一個例外引起的,

3.Error(錯誤)

  • Error 是 Throwable 的子類,用于指示合理的應用程式不應該試圖捕獲的嚴重問題,
  • 大多數這樣的錯誤都是例外條件,雖然 ThreadDeath 錯誤是一個“正規”的條件,但它也是 Error 的子類,因為大多數應用程式都不應該試圖捕獲它,
  • 在執行該方法期間,無需在其 throws 子句中宣告可能拋出但是未能捕獲的 Error 的任何子類,因為這些錯誤可能是再也不會發生的例外條件,
  • Java 程式通常不捕獲錯誤,錯誤一般發生在嚴重故障時,它們在Java程式處理的范疇之外,

4.Exception(例外)

Exception 例外主要分為兩類

  • 一類是 IOException(I/O 輸入輸出例外),其中 IOException 及其子類例外又被稱作「受查例外」
  • 另一類是 RuntimeException(運行時例外),RuntimeException 被稱作「非受查例外」,
    受查例外就是指,編譯器在編譯期間要求必須得到處理的那些例外,你必須在編譯期處理了,

5.常見的非檢查性例外

編譯器要求必須處理的例外,正確的程式在運行程序中,經常容易出現的、符合預期的例外情況,一旦發生此類例外,就必須采用某種方式進行處理,除 RuntimeException 及其子類外,其他的 Exception 例外都屬于受檢例外,編譯器會檢查此類例外,也就是說當編譯器檢查到應用中的某處可能會此類例外時,將會提示你處理本例外——要么使用try-catch捕獲,要么使用方法簽名中用 throws 關鍵字拋出,否則編譯不通過,
在這里插入圖片描述

6.常見的檢查性例外

編譯器不會進行檢查并且不要求必須處理的例外,也就說當程式中出現此類例外時,即使我們沒有try-catch捕獲它,也沒有使用throws拋出該例外,編譯也會正常通過,該類例外包括運行時例外(RuntimeException極其子類)和錯誤(Error),
在這里插入圖片描述

7.Java例外關鍵字

(1)try…catch關鍵字

  • 使用 try 和 catch 關鍵字可以捕獲例外,
  • try/catch 代碼塊放在例外可能發生的地方,

try/catch代碼塊中的代碼稱為保護代碼,使用 try/catch 的語法如下:

try {
   // 程式代碼
} catch(ExceptionName e1) {
   //Catch 塊
}
  • Catch 陳述句包含要捕獲例外型別的宣告,當保護代碼塊中發生一個例外時,try 后面的 catch 塊就會被檢查,如果發生的例外包含在 catch 塊中,例外會被傳遞到該 catch 塊,這和傳遞一個引數到方法是一樣,
  • 一個 try 代碼塊后面跟隨多個 catch 代碼塊的情況就叫多重捕獲,
  • 多重捕獲塊的語法如下所示:
try{
   // 程式代碼
}catch(例外型別1 例外的變數名1){
  // 程式代碼
}catch(例外型別2 例外的變數名2){
  // 程式代碼
}catch(例外型別2 例外的變數名2){
  // 程式代碼
}

(2) throws/throw 關鍵字

  • 如果一個方法沒有捕獲一個檢查性例外,那么該方法必須使用 throws 關鍵字來宣告,throws 關鍵字放在方法簽名的尾部,也可以使用 throw 關鍵字拋出一個例外,無論它是新實體化的還是剛捕獲到的,
  • 下面方法的宣告拋出一個 RemoteException 例外:
public class className {
  public void deposit(double amount) throws RemoteException {
    // Method implementation
    throw new RemoteException();
  }
  //Remainder of class definition
}

一個方法可以宣告拋出多個例外,多個例外之間用逗號隔開,

(3)finally關鍵字

  • finally 關鍵字用來創建在 try 代碼塊后面執行的代碼塊,
  • 無論是否發生例外,finally 代碼塊中的代碼總會被執行,在 finally 代碼塊中,可以運行清理型別等收尾善后性質的陳述句,
  • finally 代碼塊出現在 catch 代碼塊最后,語法如下:
try{
  // 程式代碼
}catch(例外型別1 例外的變數名1){
  // 程式代碼
}catch(例外型別2 例外的變數名2){
  // 程式代碼
}finally{
  // 程式代碼
}

8.宣告例外

通常,應該捕獲那些知道如何處理的例外,將不知道如何處理的例外繼續傳遞下去,傳遞例外可以在方法簽名處使用 throws 關鍵字宣告可能會拋出的例外,

注意

  • 非檢查例外(Error、RuntimeException 或它們的子類)不可使用 throws 關鍵字來宣告要拋出的例外,
  • 一個方法出現編譯時例外,就需要 try-catch/ throws 處理,否則會導致編譯錯誤,

9.拋出例外

如果你覺得解決不了某些例外問題,且不需要呼叫者處理,那么你可以拋出例外,

throw關鍵字作用是在方法內部拋出一個Throwable型別的例外,任何Java代碼都可以通過throw陳述句拋出例外,

10.捕獲例外

程式通常在運行之前不報錯,但是運行后可能會出現某些未知的錯誤,但是還不想直接拋出到上一級,那么就需要通過try…catch…的形式進行例外捕獲,之后根據不同的例外情況來進行相應的處理,

11.常見例外處理方式

(1)直接拋出例外

通常,應該捕獲那些知道如何處理的例外,將不知道如何處理的例外繼續傳遞下去,傳遞例外可以在方法簽名處使用 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();
}

(2)封裝例外再拋出

有時我們會從 catch 中拋出一個例外,目的是為了改變例外的型別,多用于在多系統集成時,當某個子系統故障,例外型別可能有多種,可以用統一的例外型別向外暴露,不需暴露太多內部例外細節,

private static void readFile(String filePath) throws MyException {    
    try {
        
    } catch (IOException e) {
        MyException ex = new MyException("read file failed.");
        ex.initCause(e);
        throw ex;
    }
}

12.捕獲例外

在一個 try-catch 陳述句塊中可以捕獲多個例外型別,并對不同型別的例外做出不同的處理

private static void readFile(String filePath) {
    try {
        
    } catch (FileNotFoundException e) {
        
    } catch (IOException e){
        
    }
}

同一個 catch 也可以捕獲多種型別例外,用 | 隔開

private static void readFile(String filePath) {
    try {
        
    } catch (FileNotFoundException | UnknownHostException e) {
        
    } catch (IOException e){
        
    }
}

13.自定義例外

習慣上,定義一個例外類應包含兩個建構式,一個無參建構式和一個帶有詳細描述資訊的建構式(Throwable 的 toString 方法會列印這些詳細資訊,除錯時很有用)

public class MyException extends Exception {
    public MyException(){ }
    public MyException(String msg){
        super(msg);
    }
    
}

14.try-catch-finally

當方法中發生例外,例外處之后的代碼不會再執行,如果之前獲取了一些本地資源需要釋放,則需要在方法正常結束時和 catch 陳述句中都呼叫釋放本地資源的代碼,顯得代碼比較繁瑣,finally 陳述句可以解決這個問題,

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 代碼塊,之后進入 finally 代碼塊;若讀取檔案時未發生例外,則會跳過 catch 代碼塊直接進入 finally 代碼塊,所以無論代碼中是否發生例外,fianlly 中的代碼都會執行,

若 catch 代碼塊中包含 return 陳述句,finally 中的代碼還會執行嗎?將以上代碼中的 catch 子句修改如下:

catch (IOException e) {
    System.out.println("readFile method catch block.");
    return;
}

呼叫 readFile 方法,觀察當 catch 子句中呼叫 return 陳述句時,finally 子句是否執行

readFile method catch block.
readFile method finally block.

可見,即使 catch 中包含了 return 陳述句,finally 子句依然會執行,若 finally 中也包含 return 陳述句,finally 中的 return 會覆寫前面的 return.

15.try-with-resource

上面例子中,finally 中的 close 方法也可能拋出 IOException, 從而覆寫了原始例外,JAVA 7 提供了更優雅的方式來實作資源的自動釋放,自動釋放的資源需要是實作了 AutoCloseable 介面的類,

private  static void tryWithResourceTest(){
    try (Scanner scanner = new Scanner(new FileInputStream("c:/abc"),"UTF-8")){
        
    } catch (IOException e){
        
    }
}

try 代碼塊退出時,會自動呼叫 scanner.close 方法,和把 scanner.close 方法放在 finally 代碼塊中不同的是,若 scanner.close 拋出例外,則會被抑制,拋出的仍然為原始例外,被抑制的例外會由 addSusppressed 方法添加到原來的例外,如果想要獲取被抑制的例外串列,可以呼叫 getSuppressed 方法來獲取,

16.Error 和 Exception 區別是什么?

Error類和Exception類的父類都是throwable類,他們的區別是:

Error類一般是指與虛擬機相關的問題,如系統崩潰,虛擬機錯誤,記憶體空間不足,方法呼叫堆疊溢等,對于這類錯誤的導致的應用程式中斷,僅靠程式本身無法恢復和預防,遇到這樣的錯誤,建議讓程式終止,

Exception類表示程式可以處理的例外,可以捕獲且可能恢復,遇到這類例外,應該盡可能處理例外,使程式恢復運行,而不應該隨意終止例外,

Exception類又分為運行時例外(Runtime Exception)和受檢查的例外(Checked Exception ),運行時例外;ArithmaticException,IllegalArgumentException,編譯能通過,但是一運行就終止了,程式不會處理運行時例外,出現這類例外,程式會終止,而受檢查的例外,要么用try…catch捕獲,要么用throws字句宣告拋出,交給它的父類處理,否則編譯不會通過,

17.Java 虛擬機是如何捕獲例外的?

在編譯生成的位元組碼中,每個方法都附帶一個例外表,例外表中的每一個條目代表一個例外處理器,并且由 form 指標,to 指標,target 指標以及所捕獲的例外型別構成,這些指標的值是位元組碼索引,用來定位位元組碼,

from 指標和 to 指標標示了該例外所監控的范圍:try 代碼塊所覆寫的范圍,
target 指標標示了例外處理器的起始位置:catch 代碼塊的起始位置,

當程式處罰例外時,Java 虛擬機會從上至下遍歷例外表中的所有條目,當觸發例外的位元組碼索引值在某個例外表條目的監控范圍內,Java 虛擬機再判斷所拋出的例外和該條目想要捕獲的例外是否匹配,如果匹配,Java 虛擬機會將控制流轉移至該條目 target 指標指向的位元組碼,

如果遍歷完例外表的條目未曾匹配到例外處理器,那么它會彈出當前方法對應的 Java 堆疊幀,并且在呼叫者中重復上述操作,

finally 代碼塊的編譯比較復雜,當前版本 Java 編譯器的做法:復制 finally 代碼塊內容,分別放在 try-catch 代碼塊所有正常執行路徑以及例外執行路徑的出口中,

在這里插入圖片描述
針對例外執行路徑,Java 編譯器會生成一個(上圖變種2)或者多個(上圖變種1)例外表條目,監控整個 try-catch 代碼塊,并且捕獲所有種類的例外,這些例外表條目的 target 指標將指向另一份復制的 finally 代碼塊(上圖變種1,變種2 中紅色 finally block),并且重新拋出捕獲的例外,

問題:如果 catch 代碼塊捕獲了例外,并且觸發了另一個例外,那么 finally 捕獲并且重拋的例外是 catch 代碼塊觸發的新的例外,原本的例外就被忽略了,這對代碼除錯來說,就不友好了,

Java 7 中引出了 Supressed 例外來解決上面的問題,這個新特性允許開發人員將一個例外附在另一個例外上,這樣拋出的例外就可以附帶多個例外的資訊,

問答
Q:為什么使用例外捕獲的代碼比較耗費性能
單從 Java 語法上看不出來,但是從 JVM 實作的細節上來看就明白了,構造例外實體,需要生成該例外的堆疊軌跡,該操作會逐一訪問當前執行緒的堆疊幀,記錄各種除錯資訊,包括類名,方法名,觸發例外的代碼行數等等,

Q:finally 是怎么實作無論例外與否都能執行
編譯器在編譯代碼時會復制 finally 代碼塊放在 try-catch 代碼塊所有正常執行路徑以及例外執行路徑的出口處,

Q:finally 中有 ruturn 陳述句,catch 中拋出的例外會被忽略,為什么
catch 拋出的例外會被 finally 捕獲,執行完 finally 后會重新拋出該例外,由于 finally 中有 return 陳述句,在重新拋出例外之前,代碼就已經回傳了,

Q:方法的例外表都包含哪些例外
方法的例外表只宣告這段代碼會被捕獲的例外,而且是非檢查例外,如果 catch 中有自定義例外,那么例外表中也會包含自定義例外的條目,

Q:檢查例外和非檢查例外也就是其他書籍中說的編譯期例外和運行時例外?
檢查例外也會在運行程序中拋出,但是它會要求編譯器檢查代碼有沒有顯式地處理該例外,非檢查例外包括Error和RuntimeException,這兩個則不要求編譯器顯式處理,

18. throw 和 throws 的區別是什么?

Java 中的例外處理除了包括捕獲例外和處理例外之外,還包括宣告例外和拋出例外,可以通過 throws 關鍵字在方法上宣告該方法要拋出的例外,或者在方法內部通過 throw 拋出例外物件,

throws 關鍵字和 throw 關鍵字在使用上的幾點區別如下

  • throw 關鍵字用在方法內部,只能用于拋出一種例外,用來拋出方法或代碼塊中的例外,受查例外和非受查例外都可以被拋出,
  • throws 關鍵字用在方法宣告上,可以拋出多個例外,用來標識該方法可能拋出的例外串列,一個方法用 throws 標識了可能拋出的例外串列,呼叫該方法的方法中必須包含可處理例外的代碼,否則也要在方法簽名中用 throws 關鍵字宣告相應的例外,

19.final、finally、finalize 有什么區別?

final是一種宣告屬性,作用與類、方法和變數;final修飾的變數的值不能夠再改變,final修飾的方面不能被覆寫,final修飾的類不能被繼承,

finally是例外處理陳述句的一部分,表示總是執行,

finalize是object類的一個子方法,在垃圾回收器執行是呼叫回收物件的此方法,此方法可以被覆寫提供資源回收時的其他資源回收,如檔案關閉等,

20.NoClassDefFoundError 和 ClassNotFoundException 區別?

在寫Java程式的時候,當一個類找不到的時候,JVM有時候會拋出 ClassNotFoundException 例外,而有時候又會拋出 NoClassDefFoundError,看兩個例外的字面意思,好像都是類找不到,但是JVM為什么要用兩個例外去區分類找不到的情況呢?這個兩個例外有什么不同的地方呢?

(1)ClassNotFoundException

ClassNotFoundException 是一個運行時例外,從類繼承層次上來看,ClassNotFoundException 是從 Exception 繼承的,所以 ClassNotFoundException 是一個檢查例外,

當應用程式運行的程序中嘗試使用類加載器去加載Class檔案的時候,如果沒有在 classpath 中查找到指定的類,就會拋出 ClassNotFoundException ,一般情況下,當我們使用Class.forName()或ClassLoader.loadClass()或ClassLoader.findSystemClass()在運行時加載類的時候,如果類沒有被找到,那么就會導致JVM拋出 ClassNotFoundException,

最簡單的,當我們使用JDBC去連接資料庫的時候,我們一般會使用Class.forName()的方式去加載JDBC的驅動,如果我們沒有將驅動放到應用的 classpath 下,那么會導致運行時找不到類,所以運行Class.forName()會拋出 ClassNotFoundException,

public class MainClass {
    public static void main(String[] args) {
        try {
            Class.forName("oracle.jdbc.driver.OracleDriver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

輸出結果:

$ java MainClass
java.lang.ClassNotFoundException: oracle.jdbc.driver.OracleDriver
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:264)
    at MainClass.main(MainClass.java:7)

(2)NoClassDefFoundError

NoClassDefFoundError 例外,看命名后綴是一個 Error ,從類繼承層次上看,NoClassDefFoundError 是從 Error 繼承的,和 ClassNotFoundException 相比,明顯的一個區別是,NoClassDefFoundError 并不需要應用程式去關心捕獲的問題,

當JVM在加載一個類的時候,如果這個類在編譯時是可用的,但是在運行時找不到這個類的定義的時候,JVM就會拋出一個 NoClassDefFoundError 錯誤,比如當我們在 new 一個類的實體的時候,如果在運行是類找不到,則會拋出一個 NoClassDefFoundError 的錯誤,

public class TempClass {
}

public class MainClass {
    public static void main(String[] args) {
        TempClass t = new TempClass();
    }
}

輸出結果:

$ java MainClass
Exception in thread "main" java.lang.NoClassDefFoundError: TempClass
    at MainClass.main(MainClass.java:6)
Caused by: java.lang.ClassNotFoundException: TempClass
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 1 more

(3)總結

ClassNotFoundExceptionNoClassDefFoundError
從java.lang.Exception繼承,是Exception型別從java.lang.Error繼承,是Error型別
當動態加載Class的時候找不到類會拋出ClassNotFoundException例外當編譯成功以后執行程序中Class找不到導致拋出NoClassDefFoundError錯誤
一般在執行Class.forName()、ClassLoader.loadClass()或ClassLoader.findSystemClass()的時候拋出由JVM的運行時拋出

21.try-catch-finally 中哪個部分可以省略?

答:catch 可以省略

原因

更為嚴格的說法其實是:try只適合處理運行時例外,try+catch適合處理運行時例外+普通例外,也就是說,如果你只用try去處理普通例外卻不加以catch處理,編譯是通不過的,因為編譯器硬性規定,普通例外如果選擇捕獲,則必須用catch顯示宣告以便進一步處理,而運行時例外在編譯時沒有如此規定,所以catch可以省略,你加上catch編譯器也覺得無可厚非,

理論上,編譯器看任何代碼都不順眼,都覺得可能有潛在的問題,所以你即使對所有代碼加上try,代碼在運行期時也只不過是在正常運行的基礎上加一層皮,但是你一旦對一段代碼加上try,就等于顯示地承諾編譯器,對這段代碼可能拋出的例外進行捕獲而非向上拋出處理,如果是普通例外,編譯器要求必須用catch捕獲以便進一步處理;如果運行時例外,捕獲然后丟棄并且+finally掃尾處理,或者加上catch捕獲以便進一步處理,

至于加上finally,則是在不管有沒捕獲例外,都要進行的“掃尾”處理,

22.try-catch-finally 中,如果 catch 中 return 了,finally 還會執行嗎?

答:會執行,在 return 前執行,

注意:在 finally 中改變回傳值的做法是不好的,因為如果存在 finally 代碼塊,try中的 return 陳述句不會立馬回傳呼叫者,而是記錄下回傳值待 finally 代碼塊執行完畢之后再向呼叫者回傳其值,然后如果在 finally 中修改了回傳值,就會回傳修改后的值,顯然,在 finally 中回傳或者修改回傳值會對程式造成很大的困擾,C#中直接用編譯錯誤的方式來阻止程式員干這種齷齪的事情,Java 中也可以通過提升編譯器的語法檢查級別來產生警告或錯誤,

代碼示例1:

public static int getInt() {
    int a = 10;
    try {
        System.out.println(a / 0);
        a = 20;
    } catch (ArithmeticException e) {
        a = 30;
        return a;
        
    } finally {
        a = 40;
    }
	return a;
}

執行結果:30

代碼示例2:

public static int getInt() {
    int a = 10;
    try {
        System.out.println(a / 0);
        a = 20;
    } catch (ArithmeticException e) {
        a = 30;
        return a;
    } finally {
        a = 40;
        
        return a; 
    }

}

執行結果:40

23.類 ExampleA 繼承 Exception,類 ExampleB 繼承ExampleA

有如下代碼片斷:

try {
	throw new ExampleB("b")
} catchExampleA e){
	System.out.println("ExampleA");
} catchException e){
	System.out.println("Exception");
}

請問執行此段代碼的輸出是什么?

輸出:ExampleA,(根據里氏代換原則[能使用父型別的地方一定能使用子型別],抓取 ExampleA 型別例外的 catch 塊能夠抓住 try 塊中拋出的 ExampleB 型別的例外)

面試題 - 說出下面代碼的運行結果,

class Annoyance extends Exception {
}
class Sneeze extends Annoyance {
}
class Human {
	public static void main(String[] args)
	throws Exception {
		try {
			try {
				throw new Sneeze();
			} catch ( Annoyance a ) {
				System.out.println("Caught Annoyance");
				throw a;
			}
		} catch ( Sneeze s ) {
			System.out.println("Caught Sneeze");
			return ;
		} finally {
			System.out.println("Hello World!");
		}
	}
}

結果

Caught Annoyance
Caught Sneeze
Hello World!

24.常見的 RuntimeException 有哪些?

NullPointerException,空指標參考例外
ClassCastException,型別強制轉換例外,
IllegalArgumentException,傳遞非法引數例外,
ArithmeticException,算術運算例外
ArrayStoreException,向陣列中存放與宣告型別不兼容物件例外
IndexOutOfBoundsException,下標越界例外
NegativeArraySizeException,創建一個大小為負數的陣列錯誤例外
NumberFormatException,數字格式例外
SecurityException,安全例外
UnsupportedOperationException,不支持的操作例外

25.Java常見例外有哪些?

ArithmeticExecption
算術例外類

NullPointerException
空指標例外類

ClassCastException
型別強制轉換例外

NegativeArrayException
陣列負下標例外

ArrayIndexOutOfBoundsException
陣列下標越界例外

SecturityException
違背安全原則例外

EOFException
檔案已結束例外

FileNotFoundException
檔案未找到例外

NumberFormatException
字串轉換為數字例外

SQLException
操作資料庫例外

IOException
輸入輸出例外

NoSuchMethodException
方法未找到例外

java.lang.AbstractMethodError
抽象方法錯誤,當應用試圖呼叫抽象方法時拋出,

java.lang.AssertionError
斷言錯,用來指示一個斷言失敗的情況,

java.lang.ClassCircularityError
類回圈依賴錯誤,在初始化一個類時,若檢測到類之間回圈依賴則拋出該例外,

java.lang.ClassFormatError
類格式錯誤,當Java虛擬機試圖從一個檔案中讀取Java類,而檢測到該檔案的內容不符合類的有效格式時拋出,

java.lang.Error
錯誤,是所有錯誤的基類,用于標識嚴重的程式運行問題,這些問題通常描述一些不應被應用程式捕獲的反常情況,

java.lang.ExceptionInInitializerError
初始化程式錯誤,當執行一個類的靜態初始化程式的程序中,發生了例外時拋出,靜態初始化程式是指直接包含于類中的static陳述句段,

java.lang.IllegalAccessError
違法訪問錯誤,當一個應用試圖訪問、修改某個類的域(Field)或者呼叫其方法,但是又違反域或方法的可見性宣告,則拋出該例外,

java.lang.IncompatibleClassChangeError
不兼容的類變化錯誤,當正在執行的方法所依賴的類定義發生了不兼容的改變時,拋出該例外,一般在修改了應用中的某些類的宣告定義而沒有對整個應用重新編譯而直接運行的情況下,容易引發該錯誤,

java.lang.InstantiationError
實體化錯誤,當一個應用試圖通過Java的new運算子構造一個抽象類或者介面時拋出該例外.

java.lang.InternalError
內部錯誤,用于指示Java虛擬機發生了內部錯誤,

java.lang.LinkageError
鏈接錯誤,該錯誤及其所有子類指示某個類依賴于另外一些類,在該類編譯之后,被依賴的類改變了其類定義而沒有重新編譯所有的類,進而引發錯誤的情況,

java.lang.NoClassDefFoundError
未找到類定義錯誤,當Java虛擬機或者類裝載器試圖實體化某個類,而找不到該類的定義時拋出該錯誤,

java.lang.NoSuchFieldError
域不存在錯誤,當應用試圖訪問或者修改某類的某個域,而該類的定義中沒有該域的定義時拋出該錯誤,

java.lang.NoSuchMethodError
方法不存在錯誤,當應用試圖呼叫某類的某個方法,而該類的定義中沒有該方法的定義時拋出該錯誤,

java.lang.OutOfMemoryError
記憶體不足錯誤,當可用記憶體不足以讓Java虛擬機分配給一個物件時拋出該錯誤,

java.lang.StackOverflowError
堆疊溢位錯誤,當一個應用遞回呼叫的層次太深而導致堆疊溢位時拋出該錯誤,

java.lang.ThreadDeath
執行緒結束,當呼叫Thread類的stop方法時拋出該錯誤,用于指示執行緒結束,

java.lang.UnknownError
未知錯誤,用于指示Java虛擬機發生了未知嚴重錯誤的情況,

java.lang.UnsatisfiedLinkError
未滿足的鏈接錯誤,當Java虛擬機未找到某個類的宣告為native方法的本機語言定義時拋出,

java.lang.UnsupportedClassVersionError
不支持的類版本錯誤,當Java虛擬機試圖從讀取某個類檔案,但是發現該檔案的主、次版本號不被當前Java虛擬機支持的時候,拋出該錯誤,

java.lang.VerifyError
驗證錯誤,當驗證器檢測到某個類檔案中存在內部不兼容或者安全問題時拋出該錯誤,

java.lang.VirtualMachineError
虛擬機錯誤,用于指示虛擬機被破壞或者繼續執行操作所需的資源不足的情況,

java.lang.ArithmeticException
算術條件例外,譬如:整數除零等,

java.lang.ArrayIndexOutOfBoundsException
陣列索引越界例外,當對陣列的索引值為負數或大于等于陣列大小時拋出,

java.lang.ArrayStoreException
陣列存盤例外,當向陣列中存放非陣列宣告型別物件時拋出,

java.lang.ClassCastException
類造型例外,假設有類A和B(A不是B的父類或子類),O是A的實體,那么當強制將O構造為類B的實體時拋出該例外,該例外經常被稱為強制型別轉換例外,

java.lang.ClassNotFoundException
找不到類例外,當應用試圖根據字串形式的類名構造類,而在遍歷CLASSPAH之后找不到對應名稱的class檔案時,拋出該例外,

java.lang.CloneNotSupportedException
不支持克隆例外,當沒有實作Cloneable介面或者不支持克隆方法時,呼叫其clone()方法則拋出該例外,

java.lang.EnumConstantNotPresentException
列舉常量不存在例外,當應用試圖通過名稱和列舉型別訪問一個列舉物件,但該列舉物件并不包含常量時,拋出該例外,

java.lang.Exception
根例外,用以描述應用程式希望捕獲的情況,

java.lang.IllegalAccessException
違法的訪問例外,當應用試圖通過反射方式創建某個類的實體、訪問該類屬性、呼叫該類方法,而當時又無法訪問類的、屬性的、方法的或構造方法的定義時拋出該例外,

java.lang.IllegalMonitorStateException
違法的監控狀態例外,當某個執行緒試圖等待一個自己并不擁有的物件(O)的監控器或者通知其他執行緒等待該物件(O)的監控器時,拋出該例外,

java.lang.IllegalStateException
違法的狀態例外,當在Java環境和應用尚未處于某個方法的合法呼叫狀態,而呼叫了該方法時,拋出該例外,

java.lang.IllegalThreadStateException
違法的執行緒狀態例外,當縣城尚未處于某個方法的合法呼叫狀態,而呼叫了該方法時,拋出例外,

java.lang.IndexOutOfBoundsException
索引越界例外,當訪問某個序列的索引值小于0或大于等于序列大小時,拋出該例外,

java.lang.InstantiationException
實體化例外,當試圖通過newInstance()方法創建某個類的實體,而該類是一個抽象類或介面時,拋出該例外,

java.lang.InterruptedException
被中止例外,當某個執行緒處于長時間的等待、休眠或其他暫停狀態,而此時其他的執行緒通過Thread的interrupt方法終止該執行緒時拋出該例外,

java.lang.NegativeArraySizeException
陣列大小為負值例外,當使用負數大小值創建陣列時拋出該例外,

java.lang.NoSuchFieldException
屬性不存在例外,當訪問某個類的不存在的屬性時拋出該例外,

java.lang.NoSuchMethodException
方法不存在例外,當訪問某個類的不存在的方法時拋出該例外,

java.lang.NullPointerException
空指標例外,當應用試圖在要求使用物件的地方使用了null時,拋出該例外,譬如:呼叫null物件的實體方法、訪問null物件的屬性、計算null物件的長度、使用throw陳述句拋出null等等,

java.lang.NumberFormatException
數字格式例外,當試圖將一個String轉換為指定的數字型別,而該字串確不滿足數字型別要求的格式時,拋出該例外,

java.lang.RuntimeException
運行時例外,是所有Java虛擬機正常操作期間可以被拋出的例外的父類,

java.lang.SecurityException
安全例外,由安全管理器拋出,用于指示違反安全情況的例外,

java.lang.StringIndexOutOfBoundsException
字串索引越界例外,當使用索引值訪問某個字串中的字符,而該索引值小于0或大于等于序列大小時,拋出該例外,

java.lang.TypeNotPresentException
型別不存在例外,當應用試圖以某個型別名稱的字串表達方式訪問該型別,但是根據給定的名稱又找不到該型別是拋出該例外,該例外與ClassNotFoundException的區別在于該例外是unchecked(不被檢查)例外,而ClassNotFoundException是checked(被檢查)例外,

java.lang.UnsupportedOperationException
不支持的方法例外,指明請求的方法不被支持情況的例外,

26.在 finally 塊中清理資源或者使用 try-with-resource 陳述句

當使用類似InputStream這種需要使用后關閉的資源時,一個常見的錯誤就是在try塊的最后關閉資源,

public void doNotCloseResourceInTry() {
    FileInputStream inputStream = null;
    try {
        File file = new File("./tmp.txt");
        inputStream = new FileInputStream(file);
        
        
        inputStream.close();
    } catch (FileNotFoundException e) {
        log.error(e);
    } catch (IOException e) {
        log.error(e);
    }
}

問題就是,只有沒有例外拋出的時候,這段代碼才可以正常作業,try 代碼塊內代碼會正常執行,并且資源可以正常關閉,但是,使用 try 代碼塊是有原因的,一般呼叫一個或多個可能拋出例外的方法,而且,你自己也可能會拋出一個例外,這意味著代碼可能不會執行到 try 代碼塊的最后部分,結果就是,你并沒有關閉資源,

所以,你應該把清理作業的代碼放到 finally 里去,或者使用 try-with-resource 特性,

27.使用 finally 代碼塊

與前面幾行 try 代碼塊不同,finally 代碼塊總是會被執行,不管 try 代碼塊成功執行之后還是你在 catch 代碼塊中處理完例外后都會執行,因此,你可以確保你清理了所有打開的資源,

public void closeResourceInFinally() {
    FileInputStream inputStream = null;
    try {
        File file = new File("./tmp.txt");
        inputStream = new FileInputStream(file);
        
    } catch (FileNotFoundException e) {
        log.error(e);
    } finally {
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (IOException e) {
                log.error(e);
            }
        }
    }
}

28.Java 7 的 try-with-resource 語法

如果你的資源實作了 AutoCloseable 介面,你可以使用這個語法,大多數的 Java 標準資源都繼承了這個介面,當你在 try 子句中打開資源,資源會在 try 代碼塊執行后或例外處理后自動關閉,

public void automaticallyCloseResource() {
    File file = new File("./tmp.txt");
    try (FileInputStream inputStream = new FileInputStream(file);) {
        
    } catch (FileNotFoundException e) {
        log.error(e);
    } catch (IOException e) {
        log.error(e);
    }
}

29.優先明確的例外

你拋出的例外越明確越好,永遠記住,你的同事或者幾個月之后的你,將會呼叫你的方法并且處理例外,

因此需要保證提供給他們盡可能多的資訊,這樣你的 API 更容易被理解,你的方法的呼叫者能夠更好的處理例外并且避免額外的檢查,

因此,總是嘗試尋找最適合你的例外事件的類,例如,拋出一個 NumberFormatException 來替換一個 IllegalArgumentException ,避免拋出一個不明確的例外,

public void doNotDoThis() throws Exception {
    ...
}
public void doThis() throws NumberFormatException {
    ...
}

30.對例外進行檔案說明

當在方法上宣告拋出例外時,也需要進行檔案說明,目的是為了給呼叫者提供盡可能多的資訊,從而可以更好地避免或處理例外,
在 Javadoc 添加 @throws 宣告,并且描述拋出例外的場景,

public void doSomething(String input) throws MyBusinessException {
    ...
}

31.使用描述性訊息拋出例外

在拋出例外時,需要盡可能精確地描述問題和相關資訊,這樣無論是列印到日志中還是在監控工具中,都能夠更容易被人閱讀,從而可以更好地定位具體錯誤資訊、錯誤的嚴重程度等,

但這里并不是說要對錯誤資訊長篇大論,因為本來 Exception 的類名就能夠反映錯誤的原因,因此只需要用一到兩句話描述即可,

如果拋出一個特定的例外,它的類名很可能已經描述了這種錯誤,所以,你不需要提供很多額外的資訊,一個很好的例子是 NumberFormatException ,當你以錯誤的格式提供 String 時,它將被 java.lang.Long 類的建構式拋出,

try {
    new Long("xyz");
} catch (NumberFormatException e) {
    log.error(e);
}

32.優先捕獲最具體的例外

大多數 IDE 都可以幫助你實作這個最佳實踐,當你嘗試首先捕獲較不具體的例外時,它們會報告無法訪問的代碼塊,

但問題在于,只有匹配例外的第一個 catch 塊會被執行, 因此,如果首先捕獲 IllegalArgumentException ,則永遠不會到達應該處理更具體的 NumberFormatException 的 catch 塊,因為它是 IllegalArgumentException 的子類,

總是優先捕獲最具體的例外類,并將不太具體的 catch 塊添加到串列的末尾,

你可以在下面的代碼片斷中看到這樣一個 try-catch 陳述句的例子, 第一個 catch 塊處理所有 NumberFormatException 例外,第二個處理所有非 NumberFormatException 例外的IllegalArgumentException 例外,

public void catchMostSpecificExceptionFirst() {
    try {
        doSomething("A message");
    } catch (NumberFormatException e) {
        log.error(e);
    } catch (IllegalArgumentException e) {
        log.error(e)
    }
}


33.不要捕獲 Throwable 類

Throwable 是所有例外和錯誤的超類,你可以在 catch 子句中使用它,但是你永遠不應該這樣做!

如果在 catch 子句中使用 Throwable ,它不僅會捕獲所有例外,也將捕獲所有的錯誤,JVM 拋出錯誤,指出不應該由應用程式處理的嚴重問題, 典型的例子是 OutOfMemoryError 或者 StackOverflowError ,兩者都是由應用程式控制之外的情況引起的,無法處理,

所以,最好不要捕獲 Throwable ,除非你確定自己處于一種特殊的情況下能夠處理錯誤,

public void doNotCatchThrowable() {
    try {
        
    } catch (Throwable t) {
        
    }
}

34.不要忽略例外

很多時候,開發者很有自信不會拋出例外,因此寫了一個catch塊,但是沒有做任何處理或者記錄日志,

public void doNotIgnoreExceptions() {
    try {
        
    } catch (NumberFormatException e) {
        
    }
}

但現實是經常會出現無法預料的例外,或者無法確定這里的代碼未來是不是會改動(洗掉了阻止例外拋出的代碼),而此時由于例外被捕獲,使得無法拿到足夠的錯誤資訊來定位問題,

合理的做法是至少要記錄例外的資訊,

public void logAnException() {
    try {
        
    } catch (NumberFormatException e) {
        log.error("This should never happen: " + e);
    }
}

35.不要記錄并拋出例外

這可能是本文中最常被忽略的最佳實踐,可以發現很多代碼甚至類別庫中都會有捕獲例外、記錄日志并再次拋出的邏輯,如下:

try {
    new Long("xyz");
} catch (NumberFormatException e) {
    log.error(e);
    throw e;
}

這個處理邏輯看著是合理的,但這經常會給同一個例外輸出多條日志,如下:

17:44:28,945 ERROR TestExceptionHandling:65 - java.lang.NumberFormatException: For input string: "xyz"
Exception in thread "main" java.lang.NumberFormatException: For input string: "xyz"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Long.parseLong(Long.java:589)
at java.lang.Long.(Long.java:965)
at com.stackify.example.TestExceptionHandling.logAndThrowException(TestExceptionHandling.java:63)
at com.stackify.example.TestExceptionHandling.main(TestExceptionHandling.java:58)

如上所示,后面的日志也沒有附加更有用的資訊,如果想要提供更加有用的資訊,那么可以將例外包裝為自定義例外,

public void wrapException(String input) throws MyBusinessException {
    try {
        
    } catch (NumberFormatException e) {
        throw new MyBusinessException("A message that describes the error.", e);
    }
}

因此,僅僅當想要處理例外時才去捕獲,否則只需要在方法簽名中宣告讓呼叫者去處理,

36.包裝例外時不要拋棄原始的例外

捕獲標準例外并包裝為自定義例外是一個很常見的做法,這樣可以添加更為具體的例外資訊并能夠做針對的例外處理,
在你這樣做時,請確保將原始例外設定為原因(注:參考下方代碼 NumberFormatException e 中的原始例外 e ),Exception 類提供了特殊的建構式方法,它接受一個 Throwable 作為引數,否則,你將會丟失堆疊跟蹤和原始例外的訊息,這將會使分析導致例外的例外事件變得困難,

public void wrapException(String input) throws MyBusinessException {
    try {
        
    } catch (NumberFormatException e) {
        throw new MyBusinessException("A message that describes the error.", e);
    }
}

37.不要使用例外控制程式的流程

不應該使用例外控制應用的執行流程,例如,本應該使用if陳述句進行條件判斷的情況下,你卻使用例外處理,這是非常不好的習慣,會嚴重影回應用的性能,

38.使用標準例外

如果使用內建的例外可以解決問題,就不要定義自己的例外,Java API 提供了上百種針對不同情況的例外型別,在開發中首先盡可能使用 Java API 提供的例外,如果標準的例外不能滿足你的要求,這時候創建自己的定制例外,盡可能得使用標準例外有利于新加入的開發者看懂專案代碼,

39.例外會影響性能

例外處理的性能成本非常高,每個 Java 程式員在開發時都應牢記這句話,創建一個例外非常慢,拋出一個例外又會消耗1~5ms,當一個例外在應用的多個層級之間傳遞時,會拖累整個應用的性能,

  • 僅在例外情況下使用例外;
  • 在可恢復的例外情況下使用例外;

盡管使用例外有利于 Java 開發,但是在應用中最好不要捕獲太多的呼叫堆疊,因為在很多情況下都不需要列印呼叫堆疊就知道哪里出錯了,因此,例外訊息應該提供恰到好處的資訊,

40.總結

綜上所述,當你拋出或捕獲例外的時候,有很多不同的情況需要考慮,而且大部分事情都是為了改善代碼的可讀性或者 API 的可用性,

例外不僅僅是一個錯誤控制機制,也是一個通信媒介,因此,為了和同事更好的合作,一個團隊必須要制定出一個最佳實踐和規則,只有這樣,團隊成員才能理解這些通用概念,同時在作業中使用它,

41.例外處理-阿里巴巴Java開發手冊

1.【強制】Java 類別庫中定義的可以通過預檢查方式規避的RuntimeException例外不應該通過catch 的方式來處理,比如:NullPointerException,IndexOutOfBoundsException等等, 說明:無法通過預檢查的例外除外,比如,在決議字串形式的數字時,可能存在數字格式錯誤,不得不通過catch NumberFormatException來實作, 正例:if (obj != null) {…} 反例:try { obj.method(); } catch (NullPointerException e) {…}

2.【強制】例外不要用來做流程控制,條件控制, 說明:例外設計的初衷是解決程式運行中的各種意外情況,且例外的處理效率比條件判斷方式要低很多,

3.【強制】catch時請分清穩定代碼和非穩定代碼,穩定代碼指的是無論如何不會出錯的代碼,對于非穩定代碼的catch盡可能進行區分例外型別,再做對應的例外處理, 說明:對大段代碼進行try-catch,使程式無法根據不同的例外做出正確的應激反應,也不利于定位問題,這是一種不負責任的表現, 正例:用戶注冊的場景中,如果用戶輸入非法字符,或用戶名稱已存在,或用戶輸入密碼過于簡單,在程式上作出分門別類的判斷,并提示給用戶,

4.【強制】捕獲例外是為了處理它,不要捕獲了卻什么都不處理而拋棄之,如果不想處理它,請將該例外拋給它的呼叫者,最外層的業務使用者,必須處理例外,將其轉化為用戶可以理解的內容,

5.【強制】有try塊放到了事務代碼中,catch例外后,如果需要回滾事務,一定要注意手動回滾事務,

6.【強制】finally塊必須對資源物件、流物件進行關閉,有例外也要做try-catch, 說明:如果JDK7及以上,可以使用try-with-resources方式,

7.【強制】不要在finally塊中使用return, 說明:try塊中的return陳述句執行成功后,并不馬上回傳,而是繼續執行finally塊中的陳述句,如果此處存在return陳述句,則在此直接回傳,無情丟棄掉try塊中的回傳點, 反例:

private int x = 0;
public int checkReturn() {
    try {
        
        return ++x;
    } finally {
        
        return ++x;
    }
}

8.【強制】捕獲例外與拋例外,必須是完全匹配,或者捕獲例外是拋例外的父類, 說明:如果預期對方拋的是繡球,實際接到的是鉛球,就會產生意外情況,

9.【強制】在呼叫RPC、二方包、或動態生成類的相關方法時,捕捉例外必須使用Throwable類來進行攔截, 說明:通過反射機制來呼叫方法,如果找不到方法,拋出NoSuchMethodException,什么情況會拋出NoSuchMethodError呢?二方包在類沖突時,仲裁機制可能導致引入非預期的版本使類的方法簽名不匹配,或者在位元組碼修改框架(比如:ASM)動態創建或修改類時,修改了相應的方法簽名,這些情況,即使代碼編譯期是正確的,但在代碼運行期時,會拋出NoSuchMethodError,

10.【推薦】方法的回傳值可以為null,不強制回傳空集合,或者空物件等,必須添加注釋充分說明什么情況下會回傳null值, 說明:本手冊明確防止NPE是呼叫者的責任,即使被呼叫方法回傳空集合或者空物件,對呼叫者來說,也并非高枕無憂,必須考慮到遠程呼叫失敗、序列化失敗、運行時例外等場景回傳null的情況,

11.【推薦】防止NPE,是程式員的基本修養,注意NPE產生的場景: 1) 回傳型別為基本資料型別,return包裝資料型別的物件時,自動拆箱有可能產生NPE, 反例:public int f() { return Integer物件}, 如果為null,自動解箱拋NPE, 2) 資料庫的查詢結果可能為null, 3) 集合里的元素即使isNotEmpty,取出的資料元素也可能為null, 4) 遠程呼叫回傳物件時,一律要求進行空指標判斷,防止NPE, 5) 對于Session中獲取的資料,建議進行NPE檢查,避免空指標, 6) 級聯呼叫obj.getA().getB().getC();一連串呼叫,易產生NPE,
正例:使用JDK8的Optional類來防止NPE問題,

12.【推薦】定義時區分unchecked / checked 例外,避免直接拋出new RuntimeException(),更不允許拋出Exception或者Throwable,應使用有業務含義的自定義例外,推薦業界已定義過的自定義例外,如:DAOException / ServiceException等,

13.【參考】對于公司外的http/api開放介面必須使用“錯誤碼”;而應用內部推薦例外拋出;跨應用間RPC呼叫優先考慮使用Result方式,封裝isSuccess()方法、“錯誤碼”、“錯誤簡短資訊”, 說明:關于RPC方法回傳方式使用Result方式的理由: 1)使用拋例外回傳方式,呼叫方如果沒有捕獲到就會產生運行時錯誤, 2)如果不加堆疊資訊,只是new自定義例外,加入自己的理解的error message,對于呼叫端解決問題的幫助不會太多,如果加了堆疊資訊,在頻繁呼叫出錯的情況下,資料序列化和傳輸的性能損耗也是問題,

14.【參考】避免出現重復的代碼(Don’t Repeat Yourself),即DRY原則, 說明:隨意復制和粘貼代碼,必然會導致代碼的重復,在以后需要修改時,需要修改所有的副本,容易遺漏,必要時抽取共性方法,或者抽象公共類,甚至是組件化, 正例:一個類中有多個public方法,都需要進行數行相同的引數校驗操作,這個時候請抽取:

private boolean checkParam(DTO dto) {…}

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/297277.html

標籤:java

上一篇:【 JavaSe 】 程式邏輯控制

下一篇:初學Java-----簡單的猜數字小游戲

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more