处理异常功能样式

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); 

当您有很多替代值时。 但是,如果表达式引发异常,则您不能做同样的事情。 可以吗

极好的

Exceptionalhttps://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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值