我注意到 for comprehension 在其内部的第一行与任何其他行抛出异常时行为不一致。
请考虑以下示例代码:
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scala.util.{Failure, Success}
object ForComprehensionTester {
def main(args: Array[String]): Unit = {
val result: Future[String] = for {
x <- returnString() // Comment out this line and exception will not be captured, but propagated.
y <- throwException()
} yield y
result.onComplete {
case Success(s) => System.out.println(s"Success: $s")
case Failure(t) => System.out.println(s"Exception captured!")
}
Thread.sleep(2000)
}
def returnString() = Future {
"content"
}
def throwException(): Future[String] = throw new RuntimeException
}
上述代码导致在 onComplete 函数中捕获和处理异常。但是如果我们注释掉第8行,那么异常将被传播。
有人可以解释发生了什么吗?
答案 0 :(得分:1)
理解是语法糖。如果您根据map
和flatMap
val result: Future[String] = for {
x <- returnString() // Comment out this line and exception will not be captured, but propagated.
y <- throwException()
} yield y
上面的代码转换为
returnString.flatMap { str =>
throwException()
}
以下是标准库中的flatMap
实现。 flatMap
处理其中抛出的异常。
def flatMap[S](f: T => Future[S])(implicit executor: ExecutionContext): Future[S] = {
import impl.Promise.DefaultPromise
val p = new DefaultPromise[S]()
onComplete {
case f: Failure[_] => p complete f.asInstanceOf[Failure[S]]
case Success(v) => try f(v) match {
// If possible, link DefaultPromises to avoid space leaks
case dp: DefaultPromise[_] => dp.asInstanceOf[DefaultPromise[S]].linkRootOf(p)
case fut => fut.onComplete(p.complete)(internalExecutor)
} catch { case NonFatal(t) => p failure t }
}
p.future
}
当你注释掉returnString
进行理解时
throwException()
请注意,throwException
抛出的异常不在函数中处理。
如下所示声明throwException
以捕获异常
def throwException(): Future[String] = Future { throw new RuntimeException }