[英]How to NOT throw an exception?
我有下面的Slick代码,给定一个ID返回一个客户(如果存在)。 如果出现问题(例如连接断开),则Failure
子句将引发异常:
def read (id: Int): Future[Option[Customer]] = {
val db = // ....
val customers = TableQuery[CustomerDB]
val action = customers.filter(_.id === id).result
val future = db.run(action.asTry)
future.map{
case Success(s) =>
if (s.length>0)
Some(s(0))
else
None
case Failure(f) => throw new Exception (f.getMessage)
}
}
现在,我的理解是,在Scala中,应该使用Try,而不是使用try / catch / finally的异常。 此外,不应引发任何异常。 但是,如果未引发异常,如何通知上层发生问题?
Future
本身已经具有内部Try。 因此,我要说的是,您只需要展平(我简化了代码,但也有点复杂):
future.flatMap {
case Success(s) => Future.successful(s.headOption)
case Failure(f) => Future.failed(f)
}
结果处于failed
状态时的Future
会通知调用者执行失败(带有原始包装异常)。 否则,成功。
报告错误的正确方法是使用Either。
trait Error
case class NotFound(id: Int) extends Error
case class QueryFailed(msg: String) extends Error
def read (id: Int): Future[Either[Error, Customer]] = {
val db = // ....
val customers = TableQuery[CustomerDB]
val action = customers.filter(_.id === id).result
val future = db.run(action.asTry)
future.map{
case Success(s) =>
if (s.length>0)
Right(s(0))
else
Left(NotFound(id))
case Failure(f) => Left(QueryFailed(f.getMessage))
}
}
好的,总的来说,您可以使用Future.successful或Future.failed(msg:String)来“信号”获得值的上层(又称调用方法)。
更好的方法
但是,一种好的方法是在失败的情况下在Future上使用.recoverWith{}
。
例如:
def getUserFromCloud (userId: String): Future[String] = Future{
cloudProviderApi.getUsername(userId)
}.recoverWith{
Future.failed(s"$userId does not exist.")
}
那调用方法呢?
好吧,您只需将成功与underscode映射,然后通过使用restore处理错误:
getUserFromCloud("test").map(_ => {
//In case of success
}).recover{
//In case of failure, like return BadRequest.
}
有关recover
和recover
更多的recoverWith
,如果您有兴趣的话: Scala恢复或recoverWith
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.