我不确定是否有一种最惯用的方式来处理 Java 的异常,因为它们至少会抛出四种不同的情况:
- 你和图书馆设计者都没有真正预料到会出错的事情出错了。
- 图书馆设计者希望能起作用的东西没有,你需要知道细节。
- 你希望的东西没有用,你不需要知道细节。
- 有时该方法会产生一个值,有时不会,它通过抛出异常来传达该值。
每种情况下的最佳实践可以说是不同的
1. 真正异常的例外
Scala 具有功能齐全的异常处理。让意外的异常传播而未被捕获并没有错,直到您达到可以对其采取措施的水平。将每一个可能的异常打包成一个Either
可能会浪费很多时间。只需记录您知道您没有处理的内容,并在适当的高级别使用 try/catch(例如,saveEverything
方法可能应该进入 try/catch 块(或将其内容包装在一个块中),因为无论出现什么问题,如果保存一切都失败了,您可能想尝试挽救局面,而不仅仅是死)。
特别是,您可能希望以Error
这种方式处理,并且只将 s 打包Exception
,而不是所有Throwable
s,放入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...
}
湾。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
的类,而不仅仅是Left
和Right
。或者您可以嵌套左侧Either
:
try { Right(/* java code */) }
catch {
case ioe: IOException => Left(Left(ioe))
case nsae: NoSuchAlgorithmException => Left(Right(nsae))
}
d。使用 Scalaz Validation
,它很像,Either
但更适合异常处理。
3. 只需要知道出了什么问题的例外情况,以及
4. 抛出异常表示无返回值
尽管它们在概念上是两个不同的类别,但您以相同的方式处理它们:
catching(classOf[IOException], classOf[NoSuchAlgorithmException]) opt { ... }
回来Option
。然后map
, flatMap
, 等等..