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