抛出异常在Future.map Scala中不起作用?

时间:2019-05-12 21:59:18

标签: scala future

def testThrowException(number: Int): Future[Int] = {
 if (number == 0) {
     throw new Exception("number is 0")
 else {
     Future{1}
 }

对于上述功能,如果我使用testThrowException(0)进行调用,则可以看到控制台中打印的异常错误消息 但是如果我做类似的事情

def testThrowException(number: Int): Future[Int] = {
anotherFuture.map {
    if (number == 0) {
        throw new Exception("number is 0")
    } else {
        1
    }
}

我看不到控制台中打印的异常 但是,如果我执行testThrowException.onFailure,则可以看到失败消息,这里我做错了什么吗?为什么没有打印出异常

3 个答案:

答案 0 :(得分:3)

在第一个示例中,异常就是这样,遇到时会抛出一个裸异常。与这样的事情没什么大不同。

def testThrowException(number: Int): Future[Int] = {
  throw new Exception("BOOM!")
  . . . //code to create a Future[Int]

第二个示例在Fututre内引发异常。异常包装在Future中,导致其失败。您将不会看到任何内容发送到控制台,但是如果您检查结果值,您应该会看到想要的内容。

res0: scala.concurrent.Future[Int] = Future(Failure(java.lang.Exception: number is 0))

答案 1 :(得分:3)

Future在单独的线程中运行,因此在Future中投掷只会使该线程崩溃,而使主线程仍在运行。例如,

object Hello extends App {
  println(s"Starting in main thread called ${Thread.currentThread.getName}...")
  Future(
    throw new RuntimeException(s"I crashed separate thread called ${Thread.currentThread.getName}")
  ).andThen { case Failure(e) => println(e.getMessage) }
  println("I made it!")
}

应输出

Starting in main thread called run-main-e...
I made it!
I crashed separate thread called scala-execution-context-global-253

我们看到它崩溃了一个名为scala-execution-context-global-253的单独线程,而主线程run-main-e仍在运行,因此I made it!可以正常打印了。另一方面,以下示例将Future

之外
object Hello extends App {
  println(s"Starting in main thread called ${Thread.currentThread.getName}...")
  throw new RuntimeException(s"I crashed the main thread ${Thread.currentThread.getName}")
  println("I made it!")
}

输出

Starting in main thread called run-main-d...
[error] (run-main-d) java.lang.RuntimeException: I crashed the main thread run-main-d

我们看到主线程run-main-d在可以打印I made it!之前崩溃了。

答案 2 :(得分:2)

第一个函数testThrowException在获得0作为输入的情况下不会返回Future。因此,该程序将一直运行直到出现异常。

但是,如下面粘贴的源代码所示,Future.map总是返回另一个未来:

  def map[S](f: T => S)(implicit executor: ExecutionContext): Future[S] = { // transform(f, identity)
    val p = Promise[S]()
    onComplete { v => p complete (v map f) }
    p.future
  }

仅定义Future不会打印其结果,也不会打印抛出的异常。为此,您需要定义onSuccessonFailureonComplete。但是,如果将来的正文中存在打印语句,则它将执行:

def addOne(number: Int): Int = {
    if (number == 0) {
        // you can also print the exception instead of just throwing it.
        throw new Exception("number is 0")
    } else {
        println("success")
        1 + number
    }
}
Future { addOne(1) } // scala.concurrent.Future[Int] = Future(Success(2))
// the above also prints "success"
Future { addOne(0) } // scala.concurrent.Future[Int] = Future(Failure(java.lang.Exception: number is 0))
// the above does not print anything unless the exception is printed before thrown in `addOne`

您也可以使用onComplete处理成功和/或失败:

// prints "got error" plus the stack trace

 - List item

Future {0}.map(addOne).onComplete {
       case Success(value) => println(s"got $value")
       case Failure(t) => println("got error: " + t.getStackTrace.mkString("\n"))
     }

请注意,使用的进口是:

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success}