Scala 恢复或 recoverWith
Scala recover or recoverWith
我们公司正在用Scala开发一些系统,有一些疑惑。我们正在讨论如何映射未来的异常,但我们不知道何时应该使用选项 1 或选项 2。
val created: Future[...] = ???
选项 1:
val a = created recover {
case e: database.ADBException =>
logger.error("Failed ...", e)
throw new business.ABusinessException("Failed ...", e)
}
选项 2:
val a = created recoverWith {
case e: database.ADBException =>
logger.error("Failed ...", e)
Future.failed(new business.ABusinessException("Failed ...", e))
}
谁能解释一下我应该什么时候做选项 1 或选项 2?有什么区别?
嗯,答案在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] = {
recover
将普通结果包装在 Future
中(类似于 map
),而 recoverWith
期望 Future
作为结果(类似于 flatMap
).
所以,这是经验法则:
如果您使用已经 returns Future
的内容恢复,请使用 recoverWith
,否则使用 recover
。
更新
在您的情况下,首选使用 recover
,因为它为您将异常包装在 Future
中。否则没有任何性能提升或任何东西,所以你只是避免一些样板。
使用 recoverWith
要求您 return 包装未来,使用 recover
要求您抛出异常。
.recoverWith # => Future.failed(t)
.recover # => throw t
我更喜欢使用 recoverWith
,因为我认为函数式编程更喜欢 returning 对象而不是抛出不像函数式风格的异常,即使它是内部代码块,我认为它仍然成立。 .
然而,如果我在恢复块中有一段内部代码可能会抛出异常,那么在这种情况下,与其捕获它并用 Future
包装它,或者尝试它,我可能会好吧 运行 这段代码与 recover
结合,它会为你处理异常包装,这将使代码更具可读性和紧凑性。
我们公司正在用Scala开发一些系统,有一些疑惑。我们正在讨论如何映射未来的异常,但我们不知道何时应该使用选项 1 或选项 2。
val created: Future[...] = ???
选项 1:
val a = created recover {
case e: database.ADBException =>
logger.error("Failed ...", e)
throw new business.ABusinessException("Failed ...", e)
}
选项 2:
val a = created recoverWith {
case e: database.ADBException =>
logger.error("Failed ...", e)
Future.failed(new business.ABusinessException("Failed ...", e))
}
谁能解释一下我应该什么时候做选项 1 或选项 2?有什么区别?
嗯,答案在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] = {
recover
将普通结果包装在 Future
中(类似于 map
),而 recoverWith
期望 Future
作为结果(类似于 flatMap
).
所以,这是经验法则:
如果您使用已经 returns Future
的内容恢复,请使用 recoverWith
,否则使用 recover
。
更新
在您的情况下,首选使用 recover
,因为它为您将异常包装在 Future
中。否则没有任何性能提升或任何东西,所以你只是避免一些样板。
使用 recoverWith
要求您 return 包装未来,使用 recover
要求您抛出异常。
.recoverWith # => Future.failed(t)
.recover # => throw t
我更喜欢使用 recoverWith
,因为我认为函数式编程更喜欢 returning 对象而不是抛出不像函数式风格的异常,即使它是内部代码块,我认为它仍然成立。 .
然而,如果我在恢复块中有一段内部代码可能会抛出异常,那么在这种情况下,与其捕获它并用 Future
包装它,或者尝试它,我可能会好吧 运行 这段代码与 recover
结合,它会为你处理异常包装,这将使代码更具可读性和紧凑性。