1.是否适合真正的异常处理?
一个有点自以为是的答案:通过异常进行的常规错误处理具有与使用可怕的 GOTO 语句类似的缺点:执行跳转到代码中的另一个特定点 - catch 语句。它比 GOTO 更好,因为它不会在完全任意点恢复执行,但必须向上调用函数调用堆栈。
使用 Either<Error, Value> 错误处理模型,您不会中断程序流程,这使代码更易于推理、更易于调试、更易于测试。
因此,我不仅会说它是合适的,而且会更好。
2. 如果是这样,您如何使用它们实现回滚?
我建议使用 Springs 事务模板: 示例:
fun <A, B> runInTransaction(block: () -> Either<A, B>): Either<A, B> {
return transactionTemplate.execute {
val result = block()
return@execute when (result) {
is Either.Left -> {
it.setRollbackOnly()
result
}
is Either.Right -> result
}
}!! // execute() is a java method which may return nulls
fun usage(): Either<String, String> {
return runInTransaction {
// do stuff
return@runInTransaction "Some error".left()
}
}
现在这很简单,因为它将任何左值视为需要回滚,您可能希望根据您的目的对其进行调整,并使用密封类来封装您希望为左案例处理的可能错误结果。
您还需要为包含此方法的类提供一个 transactionTemplate。
3. 如果问题 2. 的答案是以编程方式使用 transactionManager - 你能避免这种情况吗?
我不明白如何,因为 Springs 声明式事务管理是建立在异常错误处理模型上的,并且它对控制流的中断。
4.我把这个挤进去,你怎么避免嵌套Eithers?
您可以使用Either.fx { }
来避免任何一种嵌套。注意!用于将 Either 值绑定到 .fx 范围的语法。可以这么说,这“解包”了它们:
fun example(): Either<Error, Unit> {
return Either.fx {
val accessToken: String = !getAccessToken()
return@fx !callHttp(accessToken)
}
}
fun getAccessToken(): Either<Error, String> {
return "accessToken".right()
}
fun callHttp(token: String): Either<Error, Unit> {
return Unit.right()
}
为此,Left 值必须都是相同的类型。如果绑定了一个左值,它将被返回。这使您可以避免嵌套 when 语句或与 map/flatmap/fold 等的功能链接。