在Java中进行错误处理

yaa*_*rix 5 java error-handling functional-java either

我的新工作场所大量使用函数式Java Either进行错误处理(http://www.functionaljava.org/javadoc/4.5/functionaljava/fj/data/Either.html)。

几乎根本没有使用异常。

出于多种原因,这是非常令人讨厌的imo。举例说明:方法内的每个api调用(返回Either)必须首先检查返回的Either是否是错误,然后再继续执行下一行。如果是错误,则以Either形式将其传播回方法调用堆栈中。堆栈中的每个方法都还需要检查重新调整的Either中的错误,直到最终我们到达负责处理错误的方法为止。这导致结构非常糟糕的Java代码。我真的不能编写正常的流Java代码,因为我必须在每个api调用上“停止”(因此流不成问题)。例如

Either<Error, Value> myMethod(String someVar) {
     Either<Error, Value> valEither someService.getSomething(someVar)
     if (valEither.isRight()) {
        Either<Error, Value> otherValue someService.getSomethingElse(valEither.right().value())
        if (otherValue.isRight()) ..... //you get the idea
     } else {
        //maybe log
        return valEither;
    }
}
Run Code Online (Sandbox Code Playgroud)

我当然可以使用Either的单调方法(我也这样做),但这不能解决必须“询问”返回类型(如果有错误或值)的核心问题。为什么我认为将Either用作错误处理基础结构并不是一个好主意,原因有很多(长分配语句,长方法,嵌套泛型等)。

要解决此问题,我想到了可能会为每个正在返回“错误”的api调用抛出特定异常,然后在当前正在使用的顶级方法上捕获一次异常。

Value val = myService.getSomething().rightOrThrow(new MyException("blaa"));
Run Code Online (Sandbox Code Playgroud)

但这似乎是不可能的,因为在Either投影类型上唯一能做类似事情的方法会抛出Java错误,这并不意味着(几乎)在任何情况下都会被捕获(我可能会偶然捕获到stackoverflow或内存不足错误)。

myService.getSomething().right().valueE("some error msg");
Run Code Online (Sandbox Code Playgroud)

有什么建议或想法吗?

谢谢

Shl*_*omi 1

当我在 FJ 中编程时,我也曾短暂遇到过这个问题。我很快意识到,使用Either这种方式并不是很有帮助,而且更多的本地结构Exceptions在语法上要轻得多,并且肯定更适合该语言。

当使用函数方法(例如和等)Either组合更多功能有意义时,我确实使用过,所以类似:bimapmap

 return someService.getSomething(someVar)
  .bimap((e)-> new Error("getSomething died for " + someVar, e), 
         (x)-> someService.getSomethingElse(x))
  .right().map((x)-> someService.getSAnotherThing(x));
Run Code Online (Sandbox Code Playgroud)

也许这种构造对于支持模式匹配的语言似乎更有意义。

编辑

至于如何抛出错误,好吧,看看valueE实现,您可以简单地编写自己的静态版本来抛出您喜欢的任何错误