邪恶的Java技巧使JVM忘记检查异常
我長期以來一直批評Java中的編譯器檢查異常機制。 無論您是愛還是恨,都可以肯定一件事:在某些情況下,您不想與他們打交道。 Java中的解決方案是將一個檢查過的異常包裝在new RuntimeException(e)但這可以提供較長的堆棧跟蹤,而無需添加有用的信息。 有時,我們只想告訴編譯器冷靜。
事實證明,通過對Java泛型的類型擦除錯誤功能的某些不當(dāng)使用,這是有可能的。 看到這一點對于理解Java的內(nèi)部運作方式具有指導(dǎo)意義。 我們走吧!
這是我們想要的:
public static void main(String[] args) {businessLogic();}private static void businessLogic() {List<String> configuration = readConfigurationFile();System.out.println(configuration.get(0));}private static List<String> readConfigurationFile() {try {return Files.readAllLines(Paths.get("non", "existing", "file"));} catch (IOException e) {throw softenException(e);}}注意, businessLogic()既不捕獲IOException也不聲明它throws IOException 。 相反, softenException()方法將刪除異常的檢查。 運行它時,我們得到以下堆棧跟蹤:
Exception in thread "main" java.nio.file.NoSuchFileException: non\existing\fileat sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:79)at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102)at sun.nio.fs.WindowsFileSystemProvider.newByteChannel(WindowsFileSystemProvider.java:230)at java.nio.file.Files.newByteChannel(Files.java:361)at java.nio.file.Files.newByteChannel(Files.java:407)at java.nio.file.spi.FileSystemProvider.newInputStream(FileSystemProvider.java:384)at java.nio.file.Files.newInputStream(Files.java:152)at java.nio.file.Files.newBufferedReader(Files.java:2784)at java.nio.file.Files.readAllLines(Files.java:3202)at java.nio.file.Files.readAllLines(Files.java:3242)at insanejava.SoftenExceptionsDemo.readConfigurationFile(SoftenExceptionsDemo.java:21)at insanejava.SoftenExceptionsDemo.businessLogic(SoftenExceptionsDemo.java:15)at insanejava.SoftenExceptionsDemo.main(SoftenExceptionsDemo.java:11)! 在main方法中引發(fā)的異常是NoSuchFileException ,它是IOException的子類–已檢查的異常! 怎么可能? 為什么程序中的任何方法都不必聲明throws IOException ?
這是竅門:
private static RuntimeException softenException(Exception e) {return checkednessRemover(e);}private static <T extends Exception> T checkednessRemover(Exception e) throws T {throw (T) e;}checkednessRemover方法使用了一個技巧,可以揭示有關(guān)Java內(nèi)部工作的一些信息。 首先,將通用類型參數(shù)T綁定到RuntimeException ,以實現(xiàn)softenException 。 這意味著表達式throws T變成throws RuntimeException ,編譯器將其解釋為好像沒有拋出異常。
但是語句throw (T)e; 理論上應(yīng)該評估為throw (RuntimeException)e; 。 由于e是NoSuchFileException ,因此您希望此語句導(dǎo)致ClassCastException 。 但是,泛型在Java中的工作方式是,編譯器會刪除類型信息。 因此,字節(jié)碼改為throw (Exception)e; ,這很好。
因此,這個奇怪的把戲表明,Java編譯器從編譯的代碼中刪除了通用信息,并且檢查的異常純粹是編譯器的功能。 沒有檢查異常的運行時驗證。
我會建議在生產(chǎn)代碼中使用此技巧嗎? 我不知道。 這很奇怪,可能沒什么用,但是當(dāng)我感到邪惡時,我會自己使用它。 如果沒有別的,我希望學(xué)習(xí)可以讓您對Java的內(nèi)部運作有一些見解。
免責(zé)聲明 :(1)我在其他地方讀到了這個技巧,但是我再也找不到源了。 我以為這是Heinz Kabutz的出色Java 時事通訊,但我找不到源。 (2)這在 Lombok項目中 也實現(xiàn)為@SneakyThrows 。 如果您使用的是Lombok,則在任何情況下都不應(yīng)重新實現(xiàn)此博客中的技巧。 請改用@SneakyThrows 。
翻譯自: https://www.javacodegeeks.com/2018/05/a-wicked-java-trick-to-make-the-jvm-forget-to-check-exceptions.html
總結(jié)
以上是生活随笔為你收集整理的邪恶的Java技巧使JVM忘记检查异常的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 农业局备案(农经办备案)
- 下一篇: 端口映射ddns(端口映射ddos)