[英]Are there problems using Try or Either for error handling in public/open source Scala APIs?
我注意到许多开源Scala API使用Future
(如Slick)或Java风格的异常处理(如spray-json)而不是Try
或Either
。
在没有长时间运行或异步的简单开源API中返回Try
或Either
是否存在问题? 我应该避免这些,如果是这样,我应该使用什么呢?
(显然,我更倾向于使用核心Scala API而不是第三方库,例如Scalaz,以避免迫使下游用户使用这些库。)
Try
包装非异步操作的异常是很好的。
但是,我认为使用异常实例返回非异常错误条件是不正确的 。 当API是异步的并且使用Future
时,我也是这样。 将异常错误与业务错误混合容易导致API客户端(也就是我:)的错误处理不正确/不充分。
如果您仍然决定使用例外来表示您的业务错误,请记住异常带有隐藏价格:构建堆栈跟踪。 如果您创建自己的业务异常并混合使用scala.util.control.NoStackTrace
则可以减轻这种scala.util.control.NoStackTrace
。
Scala标准库中的默认Either
实现是无偏的,这意味着区分成功和失败的情况仅依赖于约定:
右是正确的(正确),因此左错(错误)。
不偏不倚的一面也让追随“快乐”的道路变得痛苦(或使错误恢复脱颖而出)
此时您的最佳选择(scala 2.11.6和相应的标准库)将根据您的依赖关系和要向用户公开的API而有所不同,但它不会来自scala标准库。
Validation
或\\/
是一个选项 Or
类型是一个很好的轻量级解决方案,如果你不想拉入整个scalaz。 它是成熟的,是从金字塔中提取出来的 modes
允许您让API的客户端决定他想要取回的类型(例如,这种方法在parboiled2中使用)。 我不知道图书馆作者或编译时间的成本是多少。 您可能已经依赖于提供自己的validation
类型的库。 例如,play-json有一个JsResult类型,其验证类似于能力。 根据您正在处理的内容重用类型可能是有意义的。
在以下情况下返回Try [T]:正确的结果和不正确的结果(即错误)之间存在语义差异。 这是因为:
尝试是偏右的(它适用于地图,平面地图和for-comprehensions)。
失败案例是一个Throwable,这很重要,因为throwable总是清楚地意味着甚至超出了代码边界的错误。
警告 :堆栈跟踪生成有时是一种开销,但并非总是如此! 在过早优化代码之前要三思而后行:堆栈跟踪带有许多有用的调试信息。 如果您以后发现您确实需要跳过堆栈跟踪生成,没问题:使用
with NoStackTrace
如上所示。
def validate(s:String):Try[String] = Option(s).filter(!_.isEmpty).map(Try(_)).getOrElse(new Exception("bad input") with NoStackTrace
使用[L,R]时 :两种情况都可以接受,但它们是互斥的(即[Integer,Float])。 出于这个原因,尽管Scalaz的家伙们不得不对此发表评论,但我相信这两者都是公正的。
def parseNum(s:String):Either[Int,String] = Try(parseInt(s)).map(Left(_)).getOrElse(Right(s))
类似于Either 时使用Tuple ,但是当你有N时,非互斥值(你知道所有都有用)
def parseAndReturn(s:String):(Integer,String) = (parseInt(s), s)
当 T可以为空时,或者当你处于与Try [T]相同的情况时, 返回一个选项[T] ,但是你没有给出关于为什么出错的原因。
def attemptToparse(s:String):Option[Result] = Try(parse(s)).toOption
我同意Try
是捕获/通知异常,而不是返回业务/验证错误。 Scalaz是一个非常好的选择,但是如果你不想依赖它,我认为Either
是好的,不偏不倚是令人讨厌但不是交易破坏者恕我直言:一旦你建立了Right是有效结果的约定,你可以“正确偏见”它与.rightProjection
(如果你只想处理错误,你可以做左投影。另一种选择是使用Either的折叠fold[X](fa: (A) ⇒ X, fb: (B) ⇒ X): X
myEither.fold(dealWithErrors _, happyPath _ )
fold[X](fa: (A) ⇒ X, fb: (B) ⇒ X): X
喜欢myEither.fold(dealWithErrors _, happyPath _ )
(虽然这意味着dealWithErrors
和happyPath
返回相同的类型)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.