异常作弊– Java 8 Lambdas
異常作弊– Java 8 Lambdas
撇開關于Checked vs Runtime異常的宗教辯論,有時由于庫的構造不佳,處理Checked示例會使您發瘋。
考慮一下您可能要編寫的以下代碼片段:
public void createTempFileForKey(String key) {Map<String, File> tempFiles = new ConcurrentHashMap<>();//does not compile because it throws an IOException!!tempFiles.computeIfAbsent(key, k -> File.createTempFile(key, ".tmp")); }為了使其編譯,您需要捕獲使您留下此代碼的異常:
public void createTempFileForKey(String key) {Map<String, File> tempFiles = new ConcurrentHashMap<>();tempFiles.computeIfAbsent(key, k -> {try {return File.createTempFile(key, ".tmp");}catch(IOException e) {e.printStackTrace();return null;}}); }盡管可以編譯,但是IOException已經有效地被吞沒了。 應該通知此方法的用戶已引發異常。
為了解決這個問題,您可以將IOException包裝在通用的RuntimeException中,如下所示:
public void createTempFileForKey(String key) throws RuntimeException {Map<String, File> tempFiles = new ConcurrentHashMap<>();tempFiles.computeIfAbsent(key, k -> {try {return File.createTempFile(key, ".tmp");}catch(IOException e) {throw new RuntimeException(e);}}); }這段代碼確實拋出了一個Exception,但是沒有拋出打算由該代碼拋出的實際IOException。 那些只支持RuntimeExceptions的人可能會對這段代碼感到滿意,特別是如果可以改進解決方案以創建自定義的IORuntimeException的話。 盡管如此,大多數人還是以這種方式編寫代碼,他們希望他們的方法能夠從File.createTempFile方法中拋出經過檢查的IOException 。
這樣做的自然方法有些復雜,看起來像這樣:
public void createTempFileForKey(String key) throws IOException{Map<String, File> tempFiles = new ConcurrentHashMap<>();try {tempFiles.computeIfAbsent(key, k -> {try {return File.createTempFile(key, ".tmp");} catch (IOException e) {throw new RuntimeException(e);}});}catch(RuntimeException e){if(e.getCause() instanceof IOException){throw (IOException)e.getCause();}} }從lambda內部,您必須捕獲IOException,將其包裝在RuntimeException中并拋出該RuntimeException。 Lambda必須捕獲RuntimeException的包裝并重新拋出IOException。 確實非常丑陋!
在理想的世界中,我們需要做的就是從lambda內拋出已檢查的異常,而不必更改computeIfAbsent的聲明。 換句話說,拋出檢查異常,就好像它是運行時異常一樣。 但是不幸的是,Java不允許我們這樣做……
除非我們作弊,否則那不是! 這里有兩種方法可以精確地執行我們想要的操作,即拋出檢查異常,就好像它是運行時異常一樣。
方法1 –使用泛型:
public static void main(String[] args){doThrow(new IOException());}static void doThrow(Exception e) {CheckedException.<RuntimeException> doThrow0(e);}static <E extends Exception>void doThrow0(Exception e) throws E {throw (E) e;}請注意,我們已經創建并拋出了IOException,而沒有在main方法中聲明它。
方法2 –使用不安全:
public static void main(String[] args){getUnsafe().throwException(new IOException());}private static Unsafe getUnsafe(){try {Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");theUnsafe.setAccessible(true);return (Unsafe) theUnsafe.get(null);} catch (Exception e) {throw new AssertionError(e);}}再次,我們設法拋出IOException而不在方法中聲明它。
無論您喜歡哪種方法,我們現在都可以通過這種方式自由編寫原始代碼:
public void createTempFileForKey(String key) throws IOException{Map<String, File> tempFiles = new ConcurrentHashMap<>();tempFiles.computeIfAbsent(key, k -> {try {return File.createTempFile(key, ".tmp");} catch (IOException e) {throw doThrow(e);}});}private RuntimeException doThrow(Exception e){getUnsafe().throwException(e);return new RuntimeException();}private static Unsafe getUnsafe(){try {Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");theUnsafe.setAccessible(true);return (Unsafe) theUnsafe.get(null);} catch (Exception e) {throw new AssertionError(e);}}doThrow()方法顯然將封裝在某些實用程序類中,從而使您的代碼在createTempFileForKey()非常干凈。
翻譯自: https://www.javacodegeeks.com/2015/05/cheating-with-exceptions-java-8-lambdas.html
總結
以上是生活随笔為你收集整理的异常作弊– Java 8 Lambdas的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 拼图项目的动机和目标
- 下一篇: 电脑硬盘功率多大合适(电脑硬盘功率多大合