Scala:处理来自 Java 库的异常的最佳方法?

标签 scala exception exception-handling scala-java-interop

假设我正在使用我的 Scala 项目中的 Java 库。该 Java 库会到处抛出异常,但让它们“在 Scala 世界中”传播我感到不舒服,因为无法确定 Scala 方法可以抛出哪些异常(除非通过记录它们)。所以这是我倾向于编写的代码:

def doesNotThrowExceptions(parameter: String): Either[Throwable, T] =
  catching(classOf[IOException], classOf[NoSuchAlgorithmException]) either {
    // Code calling the Java library
    // Code generating a value of type T
  }

然后,通常,我会使用 Either.RightProjection.flatMap链接返回 Either[Throwable, ...] 的方法或 Either.RightProjection.map混合返回 Either[Throwable, ...] 的方法和其他方法。或者干脆 Either.foldThrowable 做点什么值(value)。然而,不知何故,这仍然感觉不完全正确。

这是在 Scala 中处理 Java 异常的最“惯用”方式吗?没有更好的办法吗?

最佳答案

我不确定是否有一种最惯用的方法来处理 Java 的异常,因为它们至少会抛出四种不同的情况:

  • 您和库设计者都没有真正预料到会出错的事情出错了。
  • 库设计者希望行之有效的东西没有,你需要知道细节。
  • 你希望的东西没有用,你不需要知道细节。
  • 有时该方法会产生一个值,有时则不会,它通过抛出异常来传达该值。

  • 对于这些案例中的每一个,最佳实践可以说是不同的

    1. 真正的异常(exception)

    Scala 具有功能齐全的异常处理。让意外的异常传播未被发现并没有错,直到您达到可以对此做些什么的水平。将所有可能的异常打包成 Either会浪费很多时间。只需记录您知道您没有处理的内容,并在适当的高级别使用 try/catch(例如 saveEverything 方法可能应该放在 try/catch 块中(或将其内容包装在一个块中),因为无论发生了什么错误,如果保存所有内容失败,您可能想尝试挽救这种情况,而不仅仅是死亡)。

    特别是,您可能想要处理 Error以这种方式只打包 Exception ,并非所有 Throwable s,进入Either .

    2. 您需要了解的异常(exception)情况

    这就是你所说的情况,你已经就如何处理这些问题给出了一些很好的建议。正如您已经注意到的,您可以使用 catching将异常打包成 Either .然后你也可以

    一种。使用模式匹配,这会让你分开你的 Either更深入:
    doesNotThrowExceptions("par").right.map(transformData) match {
      case Left(ioe: IOException) => /* ... */
      case Left(nsae: NoSuchAlgorithmException) => /* ... */
      case Right(x) => /* ... */
      case Left(e) => throw e  // Didn't expect this one...
    }
    

    湾下变频到 Option记录错误后:
    doesNotThrowExceptions("par").left.map{ e =>
      println("You're not going to like this, but something bad happened:")
      println(e)
      println("Let's see if we can still make this work....")
    }.right.toOption
    

    C。如果异常是您的流程控制的一个非常重要的部分,Either可能还不够。您可能想要定义自己的 Either - 类似类(class),不仅仅是 LeftRight .或者您可以嵌套 Either 的左侧:
    try { Right(/* java code */) }
    catch {
      case ioe: IOException => Left(Left(ioe))
      case nsae: NoSuchAlgorithmException => Left(Right(nsae))
    }
    

    d.使用 Scalaz Validation ,这很像 Either但针对异常处理进行了更多定制。

    3. 您只需要知道出现问题的异常(exception)情况,以及

    4. 抛出异常表示无返回值

    尽管它们在概念上是两个不同的类别,但您可以以相同的方式处理它们:
    catching(classOf[IOException], classOf[NoSuchAlgorithmException]) opt { ... }
    

    获得 Option背部。然后map , flatMap , 等等..

    关于Scala:处理来自 Java 库的异常的最佳方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9291600/

    相关文章:

    java - 抛出一个有意的异常以停止在 Java 中执行程序

    Android Studio 2.1.2 渲染问题。 VectorDrawable_Delegate.nDraw

    spring - 如何在 Spring AMQP 框架下捕获 AmqpConnectException?

    oracle - 在 oracle 中格式化(或提供字符串)异常消息

    java - 批量更新异常 : the batch will not terminate

    scala - 如何在Spark SQL(DataFrame)的UDF中使用常量值

    scala - 选择Akka还是Spark进行并行处理?

    Scala 替代无限循环

    scala - 如何使用spark(scala)在文件名上应用模式匹配

    unit-testing - Laravel 资源 Controller 的 PHPUnit 测试异常