简体   繁体   English

如何不抛出异常?

[英]How to NOT throw an exception?

I have the following Slick code that given an id returns a customer (if exists). 我有下面的Slick代码,给定一个ID返回一个客户(如果存在)。 If there's a problem (such as connectivity lost) a Failure clause will throw an exception: 如果出现问题(例如连接断开),则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)
      }
   }

Now, my understanding is that instead of using try/catch/finally of exceptions, in Scala one should use Try. 现在,我的理解是,在Scala中,应该使用Try,而不是使用try / catch / finally的异常。 In addition, no exceptions should be thrown. 此外,不应引发任何异常。 But if the exception is not thrown, how to notify the upper layer that a problem occurred? 但是,如果未引发异常,如何通知上层发生问题?

Future itself does already have Try inside. Future本身已经具有内部Try。 So, I would say that you need to just flatten (also you code a bit complicated, I simplified): 因此,我要说的是,您只需要展平(我简化了代码,但也有点复杂):

  future.flatMap {
    case Success(s) => Future.successful(s.headOption)
    case Failure(f) => Future.failed(f)
  }

Result Future when in failed state notifies caller that execution failed (with wrapped original exception). 结果处于failed状态时的Future会通知调用者执行失败(带有原始包装异常)。 Otherwise, successful. 否则,成功。

The right way to do report errors is by using Either. 报告错误的正确方法是使用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))
   }
}

Ok so, in general you can use Future.successful or Future.failed(msg: String) to "signal" the upper level (aka calling method) you got the value or not. 好的,总的来说,您可以使用Future.successful或Future.failed(msg:String)来“信号”获得值的上层(又称调用方法)。

Better approach 更好的方法

A good approach is however to use .recoverWith{} on a Future in case of failure. 但是,一种好的方法是在失败的情况下在Future上使用.recoverWith{}

For example: 例如:

def getUserFromCloud (userId: String): Future[String] = Future{
  cloudProviderApi.getUsername(userId)
}.recoverWith{
  Future.failed(s"$userId does not exist.")    
}  

What about the calling method? 那调用方法呢?

Well you just map the success with and underscode and deal with the error by using recover: 好吧,您只需将成功与underscode映射,然后通过使用restore处理错误:

getUserFromCloud("test").map(_ => {
    //In case of success
}).recover{
    //In case of failure, like return BadRequest. 
}

More on recover and recoverWith in case you are interested: Scala recover or recoverWith 有关recoverrecover更多的recoverWith ,如果您有兴趣的话: Scala恢复或recoverWith

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM