![](/img/trans.png)
[英]Scala - How to send a failing response in case of an exception using Futures
[英]Scala futures and `andThen` exception propagation
我正在阅读 scala.concurrent.Future 模块中andThen
函数的 Scala 2.11.8 文档,它说如下:
def andThen[U](pf: PartialFunction[Try[T], U])
(implicit executor: ExecutionContext): Future[T]
将副作用函数应用于此未来的结果,并使用此未来的结果返回一个新的未来。
此方法允许强制以指定的顺序执行回调。
请注意,如果链接的 andThen 回调之一抛出异常,则该异常不会传播到后续的 andThen 回调。 相反,随后的 andThen 回调被赋予这个未来的原始值。
我不确定andThen
不传播异常到底是什么意思,也没有提供示例。 例如,如果我做这样的事情:
Future.successful { throw new RuntimeException("test") } andThen
{ case _ => println("test") }
在 Scala REPL 中,我得到:
java.lang.RuntimeException: test
... 32 elided
所以这个异常被传播了。 有人可以提供一个有意义的例子,这究竟意味着什么,以及使用andThen
和我想从中恢复的抛出异常的代码是否安全。 谢谢。
不要在Future.successful {}
throw
异常。
这是正确的方法
Future { throw new RuntimeException("test") } andThen
{ case _ => println("test") }
你可以通过下面这行代码来理解andThen
的用法
Future.successful { 1 } andThen { case _ => "foo" }
复制代码
@ Future.successful { 1 } andThen { case _ => "foo" }
res7: Future[Int] = Success(1)
复制代码
@ Future.successful { 1 } andThen { case _ => println("foo") }
foo
res8: Future[Int] = Success(1)
复制代码
@ val result = Future.successful { 1 } andThen { case _ => "foo" }
result: Future[Int] = Success(1)
在上面的例子中
我们可以看到执行了 andthen 之后的部分函数,但忽略了部分函数的返回类型。 最后结果输出是Future
结果,它是Future[Int]
这意味着addThen
用于在Future
完成后立即执行副作用函数。
当未来失败时
复制代码
@ val result = Future { throw new Exception("bar") } andThen { case _ => "foo" }
result: Future[Nothing] = Failure(java.lang.Exception: bar)
复制代码
@ val result = Future { throw new Exception("bar") } andThen { case _ => println("foo") }
foo
result: Future[Nothing] = Failure(java.lang.Exception: bar)
当 future 失败时也是如此。 andThen之后的代码执行and但是andThen之后的代码的结果被忽略,最终结果是Future结果。
So andThen
用于在 Future 完成后立即运行副作用代码。 andThen
也将最终输出保留为Future
的输出。
这就是andThen
在标准库中的实现方式。
andThen
驻留在Future
类中
def andThen[U](pf: PartialFunction[Try[T], U])(implicit executor: ExecutionContext): Future[T] = {
val p = Promise[T]()
onComplete {
case r => try pf.applyOrElse[Try[T], Any](r, Predef.conforms[Try[T]]) finally p complete r
}
p.future
}
1) 对这个future的结果应用副作用函数,并用这个future的结果返回一个新的future。
是的
pf
是副作用代码,因为它的输出类型没有被使用(不能被使用)。 p.future
是他所说的新未来。 Promise
以之前的Future
结果完成(看上面addThen
的实现)
在 finally 块p complete r
表示使用p.future
创建新的 Future 并使用p.future
Future 结果完成r
2) 此方法允许强制以指定的顺序执行回调。
是的。 您可以使用多个andThen
调用链接多个回调,并且这些回调按照andThen
调用的顺序依次执行。 这与onComplete
方法相比,您可以多次使用它来注册多个回调,但这些回调的顺序是不确定的。
3) 请注意,如果链接的 andThen 回调之一抛出异常,则该异常不会传播到后续的 andThen 回调。 相反,随后的 andThen 回调被赋予这个未来的原始值。
是的
r
是前一个未来的结果被赋予pf
(看上面的 andThen 代码)
我认为类型签名是最好的文档。 如您所见, andThen
接受T => U
(为简单起见省略了 PF 和 Try),并返回Future[T]
。 所以你可以想一想, andThen
执行一些效果并返回原来的未来。 因此,如果您的部分函数andThen
异常,它不会传播到其他andThen
s,它们将作用于原始未来:
import scala.concurrent.ExecutionContext.Implicits.global
Future{ 2 } andThen {
case _ => throw new RuntimeException("test")
} andThen {
case v ⇒ println("After exception"); println(v)
}
Thread.sleep(500)
这打印:
java.lang.RuntimeException: test
After exception
Success(2)
附注。 再次通读您的示例。 我想你只是最后忘记了 Thread.sleep 以便在程序结束之前完成未来。 所以你可能正确理解了一切。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.