处理异常功能样式
Java從一開始就支持檢查異常。 在Java 8中,語言元素lambda和支持流操作的RT庫修改將功能編程風格引入了該語言。 函數樣式和異常并不是真正的好朋友。 在本文中,我將描述一個簡單的庫,該庫在某種程度上類似于使用Optional處理null方式處理異常。
該庫有效(畢竟它是單個類和一些內部類,但實際上不是很多)。 另一方面,我不是絕對確定使用該庫不會降低普通程序員的編程風格。 可能會有人用錘子把所有東西都看成是釘子。 錘子不是很好的修腳工具。 看看這個庫更像是一個想法,而不是作為一個告訴您如何創建完美的代碼處理異常的最終工具。
處理檢查的異常
已檢查的異常必須像感冒一樣被聲明或捕獲。 這是與null的主要區別。 評估表達式可以靜默為null但不能靜默引發已檢查的異常。 當結果為null我們可以使用它來表示沒有值,或者我們可以檢查并使用“默認”值代替null 。 這樣做的代碼模式是
var x = expression; if ( expression == null ){ x = expression that is really never null default expression that is really never }模式表達式是相同的,盡管Java語法略有不同,但表達式的求值可能會引發檢查異常。
Type x; // you cannot use 'var' here try { x = expression } catch (Exception weHardlyEverUseThisValue){ x = expression that does not throw exception default expression that does not }如果第二個表達式也可以為null或可能引發異常,并且如果第一個表達式失敗,我們需要第三個表達式甚至更多個表達式進行評估,則結構可能會更復雜。 由于許多括號,在拋出異常的情況下,這尤其頑皮
Type x; // you cannot use 'var' here try { try { x = expression1 } catch (Exception e){ try { x = expression2 } catch (Exception e){ try { x = expression3 } catch (Exception e){ x = expression4 }}}} catch (Exception e){ x = expression that does not throw exception default expression that does not }對于null處理,我們有Optional 。 解決百萬美元的問題并不是完美的,這是設計一種既沒null又被低估的語言的名稱,但是如果使用得當,它會使生活變得更好。 (更糟糕的是,如果使用錯誤的方式,您可以隨意地說,我在本文中所描述的正是這種方式。)
如果結果表達式為null ,則可以編寫
var x = Optional.ofNullable(expresssion) .orElse( expression that does not throw exception); default expression that does not exception);你也可以寫
var x = Optional.ofNullable(expresssion1) .or( () -> Optional.ofNullable(expression2)) .or( () -> Optional.ofNullable(expression3)) .or( () -> Optional.ofNullable(expression4)) ... .orElse( expression that does not throw exception); default expression that does not exception);當您有很多替代值時。 但是,如果表達式引發異常,則您不能做同樣的事情。 可以嗎
極好的
庫Exceptional ( https://github.com/verhas/exceptional )
< groupId >com.javax0</ groupId > < artifactId >exceptional</ artifactId > < version >1.0.0</ version >實現了在Optional實現的所有方法,一個或多個實現了某些方法,并且某些方法的目的有所不同,旨在在異常情況下使用相同的方式,如上面針對null值的Optional 。
您可以使用Exceptional.of()或Exceptional.ofNullable()創建一個Exceptional值。 重要的區別在于,論點不是價值,而是提供價值的供應商。 該供應商不是JDK Supplier因為該Supplier無法引發異常,因此整個庫將無用。 此供應商必須是Exceptional.ThrowingSupplier ,它與JDK Supplier完全相同,但方法get()可能會拋出Exception 。 (另請注意,只有一個Exception ,而不是Throwable正如你用裸手搭上了燒紅的鐵球,你應該只捕捉盡可能頻繁。)
在這種情況下,您可以寫的是
var x = Exceptional.of(() -> expression) // you CAN use 'var' here .orElse( expression that does not throw exception); default expression that does not exception);它越來越短,通常更容易閱讀。 (或者不是?這就是為什么APL如此受歡迎?或者是?您問什么是APL?)
如果您有多種選擇,可以寫
var x = Exceptional.of(() -> expression1) // you CAN use 'var' here .or(() -> expression2) .or(() -> expression3) // these are also ThrowingSupplier expressions .or(() -> expression4) ... .orElse( expression that does not throw exception); default expression that does not exception);如果某些供應商可能會導致null不僅引發異常,則有方法的ofNullable()和orNullable()變體。 ( orNullable()在Optional中不存在,但在這里,如果整個庫都可以使用,則是有意義的。)
如果您熟悉Optional并使用更高級的方法,如ifPresent() , ifPresentOrElse()或orElseThrow() , stream() , map() , flatMap() , filter()那么使用Exceptional并不困難。 類中存在具有相同名稱的類似方法。 再次不同的是,如果Optional的方法的參數為Function ,則為Exceptional時為ThrowingFunction 。 利用這種可能性,您可以編寫如下代碼
private int getEvenAfterOdd( int i) throws Exception { if ( i % 2 == 0 ){ throw new Exception(); } return 1 ; } @Test @DisplayName ( "some odd example" ) void testToString() { Assertions.assertEquals( "1" , Exceptional.of(() -> getEvenAfterOdd( 1 )) .map(i -> getEvenAfterOdd(i+ 1 )) .or( () -> getEvenAfterOdd( 1 )) .map(i -> i.toString()).orElse( "something" ) ); }也可以像下面的示例一樣處理函數表達式中的異常:
private int getEvenAfterOdd( int i) throws Exception { if (i % 2 == 0 ) { throw new Exception(); } return 1 ; } @Test void avoidExceptionsForSuppliers() { Assertions.assertEquals( 14 , ( int ) Optional.of( ).map(i -> 13 ).map(i -> Exceptional.of(() -> inc(i)) .orElse( 0 )).orElse( 15 )); }最后但并非最不重要的一點是,您可以模仿?. Groovy寫作的運營商
abcdef表達式(其中所有變量/字段都可能為null并通過它們訪問下一個字段)會導致NPE。 您可以但是寫
var x = Exceptional.ofNullable( () -> abcdef).orElse( null );摘要
記住我對錘子說的話。 小心使用,并獲得更大的利益。
翻譯自: https://www.javacodegeeks.com/2019/05/handling-exceptions-functional-style.html
總結
- 上一篇: (版纳备案章)
- 下一篇: 在Spring@Component vs