两个异常"at the same time",这种情况的正确处理方法是什么?

Two exceptions "at the same time", what is the proper way to handle this situation?

我有一种情况需要调用foo方法,如果调用bar方法失败,则重新抛出原始异常(包装)。

我的问题是 bar 方法也可能失败,它的异常信息也很重要。

当我创建一个新的异常时,只有一个原因,而我有两个。我可以创建类似 class MyException(cause1, cause2) extends RuntimeException(cause1) 的内容,但 cause2 将超出异常所具有的标准机制(堆栈跟踪等)。

有没有更好的方法来处理这种情况?

下面的代码是一个简化的例子。

// I can't change this code
def foo:String = throw new FooException("foo method fails")
def bar:String = throw new BarException("bar method fails")

// my code
try {
  foo
} catch {
  case error1:FooException =>
    try {
      // if foo fails, I want to call bar
      bar
      throw new MyException("my exception", error1)
    } catch {
      case error2:BarException =>
        // but bar could fail too
        throw new MyException("my exception", ???)
        // if my cause is error1, I lost error2 information (message and stack)
        // if my cause is error2, I lost error1 information (message and stack)
    }
}

提前致谢。

您可以将 MyException throwable 与 "suppressed" 异常中的一个或两个一起打包。

val myEx = new MyException("my exception")
myEx.addSuppressed(error1)
myEx.addSuppressed(error2)
throw myEx

然后由捕获代码解包。

case err : MyException =>
  val arr :Array[Throwable] = err.getSuppressed
  // arr contains all the "suppressed" exceptions that were added,
  // stack traces and all

尽管如此,在类型系统中表达错误的可能性比将错误留给(可能不存在的)捕获代码来做正确的事情更好。

import util.Try

val res :Either[List[Throwable],String] =
  Try(foo).fold(fErr =>
    Try(bar).fold(bErr => Left(fErr::bErr::Nil), _ => Left(fErr::Nil))
  , Right(_))

您可以根据需要从那里继续。

res match {
  case Right(s)  => println(s)  //foo result string
  case Left(lst) =>
    println(lst.map(_.getMessage()).mkString(",")) //foo method fails,bar method fails
    lst.foreach(_.printStackTrace())               //both stack traces
}