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

Oli*_*hez 23 scala exception-handling exception 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
  }
Run Code Online (Sandbox Code Playgroud)

然后,通常,我将使用Either.RightProjection.flatMap链接返回Either[Throwable, ...]Either.RightProjection.map混合返回Either[Throwable, ...]方法和其他方法的方法.或者只是Either.foldThrowable价值做点什么.但不知怎的,这仍然感觉不完全正确.

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

Rex*_*err 23

我不知道有一个单一的处理Java的异常,因为有他们就会抛出至少四个不同的情况下,最习惯的方法:

  1. 你和图书馆设计师都没想出错的东西出了问题.
  2. 图书馆设计师希望工作的东西没有,你需要知道细节.
  3. 你希望工作的东西没有,你不需要知道细节.
  4. 有时候这个方法产生一个值,有时候不会产生一个值,并通过抛出异常来传达它.

对于每种情况,最佳实践都有所不同

1.真正例外

Scala具有全功能的异常处理功能.让一个意想不到的异常传播没有任何问题,直到你处于一个可以对它做某事的水平.将每个可能的例外打包成一个Either可以浪费很多时间.只记录你知道你没有处理的内容,并在适当的高级别使用try/catch(例如,一个saveEverything方法应该放在try/catch块中(或将其内容包装在一个中),因为无论出现什么问题,如果保存一切失败你可能想要试图挽救局面,而不仅仅是死亡).

特别是,您可能希望以Error这种方式处理并且只打包Exception而不是所有Throwables Either.

2.您需要了解的例外情况

这就是你所说的情况,你已经就如何处理它们提出了一些很好的建议.正如您已经注意到的那样,您可以使用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...
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

C.如果异常是流量控制中非常重要的一部分,Either可能还不够.您可能希望定义自己Either的类,而不仅仅是LeftRight.或者你可以嵌套左边的Either:

try { Right(/* java code */) }
catch {
  case ioe: IOException => Left(Left(ioe))
  case nsae: NoSuchAlgorithmException => Left(Right(nsae))
}
Run Code Online (Sandbox Code Playgroud)

d.使用Scalaz Validation,这很像,Either但是为异常处理量身定做了更多.

3.例外,你只需要知道出错的地方,并且

4.抛出异常表示无回报价值

尽管这些在概念上是两个不同的类别,但您可以采用相同的方式处理它们:

catching(classOf[IOException], classOf[NoSuchAlgorithmException]) opt { ... }
Run Code Online (Sandbox Code Playgroud)

得到一个Option回来.然后map,flatMap等.


mis*_*tor 6

我总是喜欢scalaz.Validationscala.Either.这两个是代数相同的结构,但前者功能更丰富(有更多有用的方法和类型类实例).

查看此链接,了解Chris Marshall scalaz.Validation和其他Scalaz好东西的精彩演示.

为了与使用经典异常处理机制的代码交谈,我定义了以下丰富方法和类型类实例:

implicit def catchW[A](underlying: Catch[A]) = new CatchW(underlying)

class CatchW[A](underlying: Catch[A]) {
  def validation(body: => A): Validation[Throwable, A] = {
    underlying.withApply(_.fail)(body.success)
  }

  def vnel(body: => A): ValidationNEL[Throwable, A] = {
    underlying.withApply(_.failNel)(body.success)
  }
}

implicit def catchMonoid[A] = new Monoid[Catch[A]] {
  val zero = noCatch
  def append(x: Catch[A], y: => Catch[A]) = x or y
}
Run Code Online (Sandbox Code Playgroud)

  • Validation.fromTryCatch()在v7中,使它更好. (3认同)