Lombok的@SneakyThrows詳解


Lombok的@SneakyThrows詳解

一、簡介

​ 在java的異常體系中Exception異常有兩個分支,一個是運行時異常RuntimeException,一個是編譯時異常,在Exception下的所有非RuntimeException異常,比如IOExceptionSQLException等;所有的運行時異常不捕獲,編譯時異常是一定要捕獲,否則編譯會報錯。@SneakyThrows就是利用了這一機制,將當前方法拋出的異常,包裝成RuntimeException,騙過編譯器,使得調用點可以不用顯示處理異常信息。

二、原理

/*
 * 若不使用@SneakyThrows注解,newInsstance方法會要求拋出InstantiationException, 
 * IllegalAccessException異常,且調用sneakyThrowsTest()的地方需要捕獲這些異常,
 * 加上@SneakyThrows注解之后就不需要捕獲異常信息。
 */
@SneakyThrows
private void sneakyThrowsTest(){
  SneakyThrowsDemo.class.newInstance();
}

如下為反編譯之后的結果

private void sneakyThrowsTest() {
    try {
      HelloController.class.newInstance();
    } catch (Throwable e) {
      // 調用Lombok方法轉化為RuntimeException
      throw Lombok.sneakyThrow(e);
    }
}


// =========== ombok =========
public static RuntimeException sneakyThrow(Throwable t) {
  if (t == null) {
    throw new NullPointerException("t");
  } else {
    return Lombok.<RuntimeException>sneakyThrow0(t);
  }
}

/*
 * 這個方法是關鍵,這里對入參類型的約束為<T extends Throwable>,將異常強轉為T類型
 */
private static <T extends Throwable> T sneakyThrow0(Throwable t) throws T {
  throw (T)t;
}

那么問題來了,為什么這個地方可以對原來的異常進行強轉為RuntimeExcption?以下為直接強轉的代碼,顯然運行之后報類型轉換異常。

private void sneakyThrowsTest() {
  try {
    throw new Exception();
  } catch (Throwable e) {
    // 直接將e強轉為RuntimeException,運行到這里會報類型轉換異常。
    throw (RuntimeException)e;
  }
}

實際上,這種做法是一種通過泛型欺騙了編譯器,讓編譯器在編譯期不報錯,而最后在JVM虛擬機中執行的字節碼的並沒有區別編譯時異常和運行時異常,只有是不是和拋不拋異常而已。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM