代码之家  ›  专栏  ›  技术社区  ›  Sebastian Celestino

两个例外“同时发生”,如何处理这种情况?

  •  2
  • Sebastian Celestino  · 技术社区  · 7 年前

    我有个情况需要打电话给你 foo bar

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

    class MyException(cause1, cause2) extends RuntimeException(cause1) cause2 将超出异常具有的标准机制(stacktrace等)。

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

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

    // 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)
        }
    }
    

    先谢谢你。

    1 回复  |  直到 7 年前
        1
  •  2
  •   jwvh    7 年前

    你可以收拾行李 MyException 与一个或两个“被抑制的”异常一起抛出。

    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
    }