Scala期货和`andThen`exception传播

我在scala.concurrent.Future模块中阅读了Scala 2.11.8和andThen函数的文档,它说如下:

 def andThen[U](pf: PartialFunction[Try[T], U]) (implicit executor: ExecutionContext): Future[T] 

将副作用函数应用于此未来的结果,并返回具有此未来结果的新未来。

此方法允许强制执行回调以指定顺序执行。

请注意,如果链接的andThen回调之一抛出exception,则该exception不会传播到后续的andThen回调。 相反,后续的andThen回调将被赋予此未来的原始值。

我不确定它是什么意思是exception不会被传播, andThen也没有提供示例。 例如,如果我做这样的事情:

 Future.successful { throw new RuntimeException("test") } andThen { case _ => println("test") } 

在Scala REPL中我得到:

 java.lang.RuntimeException: test ... 32 elided 

所以exception被传播了。 有人可以提供一个有意义的例子,这究竟意味着什么,以及是否安全使用andThen代码,我抛出exception,我想从中恢复。 谢谢。

不要在Future.successful {} throwexception。

这是正确的方法

 Future { throw new RuntimeException("test") } andThen { case _ => println("test") } 

您可以使用以下代码行来理解和使用

 Future.successful { 1 } andThen { case _ => "foo" } 

REPL

 @ Future.successful { 1 } andThen { case _ => "foo" } res7: Future[Int] = Success(1) 

REPL

 @ Future.successful { 1 } andThen { case _ => println("foo") } foo res8: Future[Int] = Success(1) 

REPL

 @ val result = Future.successful { 1 } andThen { case _ => "foo" } result: Future[Int] = Success(1) 

在上面的例子中

我们可以看到在执行andhhen之后的部分函数,​​但忽略了部分函数返回类型。 最后,结果输出是Future结果,即Future[Int]

这意味着addThen用于在Future完成后执行副作用function。

当未来是一个失败

REPL

 @ val result = Future { throw new Exception("bar") } andThen { case _ => "foo" } result: Future[Nothing] = Failure(java.lang.Exception: bar) 

REPL

 @ val result = Future { throw new Exception("bar") } andThen { case _ => println("foo") } foo result: Future[Nothing] = Failure(java.lang.Exception: bar) 

未来是失败的情况也是如此。 然后执行代码,然后执行,然后忽略andThen之后的代码结果,最终结果是Future结果。

因此,当Future完成后, andThen用于运行副作用代码。 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)将副作用函数应用于此未来的结果,并返回具有此未来结果的新未来。

pf是副作用代码,因为它的输出类型未被使用(不能使用)。 p.future是他正在谈论的新未来。 Promise与之前的Future结果一起完成(请看上面的addThen的实现)

在finally块内部p complete r意味着使用p.future创建新的Future,并使用之前的结果(即r

2)此方法允许强制执行回调以指定顺序执行。

是。 pf在前一个未来完成后执行。 查看代码pf是在onComplete块中执行的。

3)注意,如果链接的andThen回调之一抛出exception,则该exception不会传播到后续的andThen回调。 相反,后续的andThen回调将被赋予此未来的原始值。

r是前一个未来的结果给pf (看看上面的andThen代码)

我认为类型签名是最好的文档。 如你所见, andThen接受T => U (省略PF和为简单起见),并给出Future[T] 。 所以你可以想到它,然后andThen执行一些效果并回归原始的未来。 因此,如果你的部分function上升exception,它将不会传播给其他andThen然后他们会对原始未来采取行动:

  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) 

PS。 再次阅读您的示例。 我想你最后忘记了Thread.sleep,以便在程序结束之前完成未来。 所以你可能正确理解了一切。