[英]Picking the right exception handling in scala
我是Scala的新手,在处理异常的各种方法上有些困惑,并在寻找有关该主题的最佳实践建议。 我正在编写一个使用现有阻止SDK检索客户的简单方法。 可能的结果是:
所以我希望我的方法有一个返回类型Future[Option[Customer]]
,并返回上面的每个案例:
这是我用try / catch写的:
private def findCustomer(userId: Long): Future[Option[Customer]] = future {
try {
Some(gateway.find(userId))
} catch {
case _: NotFoundException => None
}
}
这工作正常,对我来说似乎很干净,但似乎并不是真正的“Scala方式” - 我被告知要避免使用try / catch。 所以我一直在寻找一种方法来使用Try
来重写它。
这里有2个变体(我认为)表现完全相同,使用Try
。
变式A:
private def findCustomer(userId: Long): Future[Option[Customer]] = future {
Try(
Some(gateway.find(userId))
).recover {
case _: NotFoundException => None
}.get
}
变式B:
private def findCustomer(userId: Long): Future[Option[Customer]] = future {
Try(
Some(gateway.find(userId))
).recover {
case _: NotFoundException => None
}
} flatMap {
case Success(s) => Future.successful(s)
case Failure(f) => Future.failed(f)
}
我不是A的忠实粉丝(尽管它比B更简洁),因为.get
似乎有点奸诈。 B绝对是最明确的,但将Try
案例映射到相应的Future
结果似乎很无聊。
经验丰富的Scala程序员如何写这个?
我认为使用try/catch
初始版本非常好,因为它是现有SDK的包装器。
或者,您可以在Future
上使用recover
方法:
def findCustomer(userId: Long): Future[Option[Customer]] =
Future(Option(gateway.find(userId))).recover {
case e: NotFoundException => None
}
一种选择是避免链接Try和Future。 从某种意义上说,未来是异步尝试。
您可以直接使用Future [Customer]并将NotFoundException视为要从而不是None值进行恢复。 通常情况下,您可以将操作链接到未来本身,而无需处理故障情况(通过映射等)。 这一切都取决于你将如何使用它(未来完成时你的逻辑如何分支)。 换句话说,也许它似乎对你来说很复杂,因为它是,并且你强迫它通过强制Future [Option [Customer]]返回类型。
能够连接多个操作并继续进行计算,当且仅当所有这些都是正确的时候才是Scala的一个很好的特性(特别是对于理解等)。
您可能正在寻找:
Future.fromTry(myTry)
因此,对于您的示例,您可能会:
Future.fromTry {
Try(Some(gateway.find(userId))).recover {
case _: NotFoundException => None
}
}
要仅捕获NotFoundException
,就像在解决方案中一样。 这里唯一的问题是该方法不会异步执行。 如果有必要,请考虑使用Ionut建议的Future.recover
。
另一个值得一提的惯用选项是使用Either[F, S]
,其中S
是成功返回的类型, F
可以保存错误(您可能希望传播)。 因此,您可以使用Either[ Exception, Option[String]]
或Either[String, Option[String]]
,其中第一个String
是错误消息。
如果你准备采用一些scalaz 。 与scalaz脱节在处理错误情景时非常有用和自然。 它就像scala Either
但是scalaz disjunction \\/
是正确的偏见。 你将获得正确的成功价值和左边的例外。 使用\\/.fromTryCatch
包装代码块会在\\/.fromTryCatch
取的左侧返回异常。 权利总是有成功价值。 映射over disjunction比Scala更容易,因为析取是正确的偏差,并且很容易从右边给你价值。
import scalaz.\/
private def findCustomer(userId: Long): Future[\/[Throwable,Option[Customer]] ]= future {
\/.fromTryCatch {
Some(gateway.find(userId))
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.