【问题标题】:throw exception does not work inside future.map scala?抛出异常在future.map scala中不起作用?
【发布时间】:2019-09-29 21:49:27
【问题描述】:
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,我可以看到失败消息,我在这里做错了什么吗?为什么没有打印出异常

【问题讨论】:

    标签: scala future


    【解决方案1】:

    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】:

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

      但是,如下面粘贴的源代码所示,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。但是,如果 Future 的主体中存在 print 语句,那么它将执行:

      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}
      

      【讨论】:

        【解决方案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))
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-09-25
          • 1970-01-01
          • 1970-01-01
          • 2021-03-15
          • 2021-04-16
          • 1970-01-01
          • 2016-02-21
          • 2018-10-18
          相关资源
          最近更新 更多