Scala 猫异常处理

问题描述 投票:0回答:2

为什么它不捕获并打印来自calculateTwo的异常消息?如果我们让calculateOne抛出异常,异常就会被捕获并打印消息。

package com.oxo.test

import cats.data.EitherT
import cats.implicits._

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future

object FutureError extends App {

  try {
    (for {
      result      <- EitherT(calculateOne())
      resultTwo   <- EitherT(calculateTwo())
      resultThree <- EitherT(calculateThree())
      sum          = result + resultTwo + resultThree
    } yield {
      sum
    })
  } catch {
    case e: Exception => println(e.getMessage)
  }

  private def calculateOne(): Future[Either[String, Int]] = {
    //throw new RuntimeException("error from one")
    Future.successful(Right(1))
  }

  private def calculateTwo(): Future[Either[String, Int]] = {
    throw new RuntimeException("error from two")
    //Future.successful(Right(2))
  }

  private def calculateThree(): Future[Either[String, Int]] = {
    //throw new RuntimeException("error from three")
    Future.successful(Right(3))
  }

}
scala scala-cats
2个回答
0
投票

EitherT
try ... catch
是两种完全正交的异常处理机制。为了处理像
EitherT
这样的结果类型类型的异常,我们只需调用类上的方法,而不是使用特殊的控制构造。例如,根据您的情况,
getOrElse
是一个不错的选择。

(for {
  result      <- EitherT(calculateOne())
  resultTwo   <- EitherT(calculateTwo())
  resultThree <- EitherT(calculateThree())
  sum          = result + resultTwo + resultThree
} yield {
  sum
}).getOrElse(whateverDefaultValue)

请记住,处理异常并不意味着您可以返回适当类型的值。如果

sum
Int
,则处理错误条件 also 的结果也需要是
Int
。如果在这种情况下你没有返回
Int
,那么你就没有处理异常;你正在传播它。


0
投票

正如其他人所说:将

throw/try..catch
Future/Either/EitherT
混合是自找麻烦。坚持使用一种或另一种型号。


现在,让我们了解代码中发生了什么。

您的示例可以简化为以下代码,其行为方式相同:

calculateOne()
  .flatMap(_ => calculateTwo())

calculateTwo()
将在
Future
中“执行”,任何异常都会被
Future
吞噬并产生
Future.failed
。它与您所写的大致相同:

calculateOne.flatMap { _ =>
  Future { 
    throw new Exception(...)
  }
}

其本身大致相同于:

calculateOne.flatMap { _ =>
  Future.failed(new Exception(...)) // no throw!
}

整体表达结果无一例外,只是一个

Future.failed


现在,如果

calculateOne()
抛出异常,它还没有“进入”
Future
并且大致与:

相同
throw new Exception(...)
calculateTwo() // not even called, dead code

这只是抛出异常。

它不一样:

Future.failed(new Exception())
  .flatMap(_ => calculateTwo())

这不会导致任何异常,但会失败

Future

© www.soinside.com 2019 - 2024. All rights reserved.