Scala恢复或恢复

Hen*_*art 41 scala

我们正在Scala开发一些系统,我们有一些疑问.我们正在讨论如何映射未来的异常,我们不知道何时应该使用选项1或选项2.

val created: Future[...] = ???
Run Code Online (Sandbox Code Playgroud)

选项1:

val a = created recover {   
  case e: database.ADBException =>
    logger.error("Failed ...", e)
    throw new business.ABusinessException("Failed ...", e) 
}
Run Code Online (Sandbox Code Playgroud)

选项2:

val a = created recoverWith {   
  case e: database.ADBException =>
    logger.error("Failed ...", e)
    Future.failed(new business.ABusinessException("Failed ...", e))
}
Run Code Online (Sandbox Code Playgroud)

有人可以解释我何时应该选择1还是选项2?什么是差异?

Aiv*_*ean 69

嗯,scaladocs中清楚地描述了答案:

  /** Creates a new future that will handle any matching throwable that this
   *  future might contain. If there is no match, or if this future contains
   *  a valid result then the new future will contain the same.
   *
   *  Example:
   *
   *  {{{
   *  Future (6 / 0) recover { case e: ArithmeticException => 0 } // result: 0
   *  Future (6 / 0) recover { case e: NotFoundException   => 0 } // result: exception
   *  Future (6 / 2) recover { case e: ArithmeticException => 0 } // result: 3
   *  }}}
   */
  def recover[U >: T](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Future[U] = {

  /** Creates a new future that will handle any matching throwable that this
   *  future might contain by assigning it a value of another future.
   *
   *  If there is no match, or if this future contains
   *  a valid result then the new future will contain the same result.
   *
   *  Example:
   *
   *  {{{
   *  val f = Future { Int.MaxValue }
   *  Future (6 / 0) recoverWith { case e: ArithmeticException => f } // result: Int.MaxValue
   *  }}}
   */
  def recoverWith[U >: T](pf: PartialFunction[Throwable, Future[U]])(implicit executor: ExecutionContext): Future[U] = {
Run Code Online (Sandbox Code Playgroud)

recoverFuture为你(类似的map)包装简单的结果,同时recoverWith期望Future作为结果(类似flatMap).

所以,这里有经验法则:

如果您使用已经返回的内容进行恢复Future,请使用recoverWith,否则请使用recover.

更新 在您的情况下,recover首选使用,因为它Future为您包装异常.否则没有性能增益或任何东西,所以你只需要避免一些样板.


Tom*_*vid 14

使用recoverWith你被要求返回一个包裹的未来,使用recover你被要求抛出异常.

.recoverWith # => Future.failed(t)
.recover # => throw t
Run Code Online (Sandbox Code Playgroud)

我更喜欢使用recoverWith,因为我认为函数式编程更喜欢返回对象不是抛出异常是少了实用的风格,即使它的内部代码块,我认为它仍然持有..

但是,如果我在恢复块中有一段内部代码可能会引发异常,那么在这种情况下,不管是捕获它还是将其包装起来Future,或者尝试它,我不妨只运行这段代码.recover它会为你处理异常包装,这将使代码更具可读性和紧凑性.