Scala 期货和 `andThen` 异常传播

flo*_*dek 6 java scala exception-handling future exception

我正在阅读andThenscala.concurrent.Future 模块中函数的Scala 2.11.8 文档,它说如下:

def andThen[U](pf: PartialFunction[Try[T], U])
              (implicit executor: ExecutionContext): Future[T]
Run Code Online (Sandbox Code Playgroud)

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

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

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

我不确定异常不传播的确切含义是什么,andThen也没有提供示例。例如,如果我做这样的事情:

Future.successful { throw new RuntimeException("test") } andThen
                  { case _ => println("test") }
Run Code Online (Sandbox Code Playgroud)

在 Scala REPL 中,我得到:

java.lang.RuntimeException: test
  ... 32 elided
Run Code Online (Sandbox Code Playgroud)

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

pam*_*amu 6

不要throwFuture.successful {}.

这是正确的方法

Future { throw new RuntimeException("test") } andThen
                  { case _ => println("test") }
Run Code Online (Sandbox Code Playgroud)

andThen使用下面这行代码就可以理解使用了

Future.successful { 1 } andThen { case _ =>  "foo" }
Run Code Online (Sandbox Code Playgroud)

复制代码

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

复制代码

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

复制代码

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

在上面的例子中

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

此方法addThen用于在Future完成后立即执行副作用功能。

当未来失败时

复制代码

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

复制代码

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

当 future 失败时也是如此。andThen之后的代码执行and但是andThen之后的代码的结果被忽略,最终结果是Future结果。

SoandThen用于在 Future 完成后立即运行副作用代码。andThen还将最终输出保留为Futures 输出。

这是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
  }
Run Code Online (Sandbox Code Playgroud)

1) 对这个future的结果应用副作用函数,并用这个future的结果返回一个新的future。

是的

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

在 finally 块中p complete r意味着新的 Future 是使用创建的p.future,它是使用之前的Future结果完成的,它是r

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

是的。您可以使用多个andThen调用链接多个回调,并且这些回调按照andThen调用的顺序依次执行。这与onComplete您可以多次使用它来注册多个回调的方法相比,但这些回调的顺序是不确定的。

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

是的

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