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.fold对Throwable价值做点什么.但不知怎的,这仍然感觉不完全正确.
这是处理Scala中Java异常的最"惯用"方式吗?有没有更好的方法?
Rex*_*err 23
我不知道有一个单一的处理Java的异常,因为有他们就会抛出至少四个不同的情况下,最习惯的方法:
对于每种情况,最佳实践都有所不同
Scala具有全功能的异常处理功能.让一个意想不到的异常传播没有任何问题,直到你处于一个可以对它做某事的水平.将每个可能的例外打包成一个Either可以浪费很多时间.只记录你知道你没有处理的内容,并在适当的高级别使用try/catch(例如,一个saveEverything方法应该放在try/catch块中(或将其内容包装在一个中),因为无论出现什么问题,如果保存一切失败你可能想要试图挽救局面,而不仅仅是死亡).
特别是,您可能希望以Error这种方式处理并且只打包Exception而不是所有Throwables Either.
这就是你所说的情况,你已经就如何处理它们提出了一些很好的建议.正如您已经注意到的那样,您可以使用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的类,而不仅仅是Left和Right.或者你可以嵌套左边的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但是为异常处理量身定做了更多.
尽管这些在概念上是两个不同的类别,但您可以采用相同的方式处理它们:
catching(classOf[IOException], classOf[NoSuchAlgorithmException]) opt { ... }
Run Code Online (Sandbox Code Playgroud)
得到一个Option回来.然后map,flatMap等.
我总是喜欢scalaz.Validation了scala.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)