scala - Scala 中有抑制异常吗?

标签 scala exception try-with-resources

在Scala中,我们可以将finally block 中的异常抛出添加回原始异常作为抑制异常吗?

在Java中,如果我们在try block 中遇到异常,然后在finally block 中遇到另一个异常,则第二个异常将作为抑制异常添加回第一个异常。因此,第二个异常不会掩盖第一个异常,我们仍然可以通过检查其抑制的异常来分析发生了什么。

import java.util.stream.Stream;

class Scratch {
    static class MyCloseable implements AutoCloseable {
        @Override
        public void close() throws Exception {
            throw new Exception("FROM CLOSE METHOD");
        }
    }

    public static void main(String[] args) {

        try {
            try (final MyCloseable closeable = new MyCloseable()){
                throw new Exception("From Try Block");
            }
        } catch (Throwable t) {
            System.out.println(t);
            Stream.of(t.getSuppressed()).forEach(System.out::println);
        }
    }
}

会抛出异常

  • java.lang.Exception:来自 Try block
  • java.lang.Exception:来自 CLOSE 方法

但是,Scala 似乎只是重新抛出第二个异常(从 finally block 抛出)并忽略第一个异常(从 try block 抛出)。

try {
  try {
    throw new Exception("From Try Block")
  } finally {
    throw new Exception("From Final Block")
  }
} catch {
  case e => e :: e.getSuppressed().toList
}

上面的代码将仅返回第二个异常(从最终 block 抛出)。但是,我希望有一种方法可以同时获得两个异常。

有什么办法可以更好地编写上面的代码吗?

最佳答案

由于 Scala 不支持 java 的 try-with-resources 构造,我想有一个明显的方法可以使上面的代码以更好的方式 = 记住第一个异常:

    try {
      var te: Option[Throwable] = None
      try {
        throw new Exception("From Try Block")
      } catch {
        case t: Throwable =>
          te = Some(t)
          throw t
      } finally {
        try {
          throw new Exception("From Final Block")
        } catch {
          case fe: Throwable =>
            throw te.map { e => e.addSuppressed(fe); e }.getOrElse(fe)
        }
      }
    } catch {
      case e: Throwable =>
        (e :: e.getSuppressed().toList).foreach(println)
    }

输出:

java.lang.Exception: From Try Block
java.lang.Exception: From Final Block

下面是我在实际项目中使用的更好的方法:

  def withResources[T <: AutoCloseable, V](r: => T)(f: T => V): V = {
    val resource: T = r
    var e: Option[Throwable] = None

    try f(resource)
    catch {
      case t: Throwable =>
        e = Some(t)
        throw t
    } finally e.fold(resource.close())(te =>
      try resource.close()
      catch {
        case t: Throwable =>
          te.addSuppressed(t)
          throw te
      })
  }
    val resource = new AutoCloseable {
      override def close(): Unit = throw new Exception("From Final Block")
    }

    try {
      withResources(resource)(_ => throw new Exception("From Try Block"))
    } catch {
      case e: Throwable =>
        (e :: e.getSuppressed().toList).foreach(println)
    }

输出:

java.lang.Exception: From Try Block
java.lang.Exception: From Final Block

关于scala - Scala 中有抑制异常吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56064395/

相关文章:

java - 使用 try-with-resources 时是否需要调用 flush()

scala - 如何分析在SBT中完成任务所花费的时间

scala - 执行器占用的内存超出了定义

java - Android Java 异常 - 手动抛出时它们如何工作?

java.rmi.ServerException : RemoteException occurred in server thread (ClassNotFoundException)

java - 尝试资源的 8 个分支 - 可以进行 jacoco 覆盖吗?

scala - Stream Continually 只读取 1 分钟

scala - 您可以删除 Lift CRUDify 表单上的 "View/Edit/Delete"链接吗?

python - 如何在引发时将变量传递给异常并在异常时检索它?

java - 如何使用 Try-with-Resources 两次使用 PreparedStatement?