5

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

几乎根本不使用异常。

由于许多原因,这很烦人。举个例子:方法内的每个 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;
    }
}

当然,我可以使用 Either 的一元方法(我会这样做),但这并不能解决必须“询问”返回类型是否为错误或值的核心问题。我认为使用 Either 作为错误处理的基础设施不是一个好主意的原因还有很多(长赋值语句、长方法、嵌套泛型等)。

为了解决这个问题,我想可能会为每个返回“错误”的api调用抛出一个特定的异常,并在我目前正在处理的顶级方法上捕获一次异常。

Value val = myService.getSomething().rightOrThrow(new MyException("blaa"));

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

myService.getSomething().right().valueE("some error msg");

有什么建议或想法吗?

谢谢

4

2 回答 2

1

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

Either当使用函数方法(例如bimap和等)组合进一步的功能有意义时,我确实使用过map,所以类似于:

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

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

编辑

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

于 2017-04-25T06:36:52.237 回答
0

如果返回的 Either 是错误,我发现抛出异常的最佳解决方案是:

either.right.on(err -> {throw new MyException(err);})

或使用辅助方法使其更具可读性:

 static <A> A willFailWith(String errorMsg) {
       throw new MyException(errorMsg);
 }
 either.right.on(err -> willFailWith(err))
于 2017-04-27T13:09:36.527 回答