Javaのtry-catch-finally
は致命的なエラー(FatalError)は捕捉しませんが、
Scalaのtry-catch-finally
は致命的なエラーも捕捉してしまいます。
致命的な例外として有名なのはOutOfMemoryError
などがあり、このような致命的な例外はプログラム中で捕捉すべきではありません。
scala> try {
| throw new StackOverflowError
| } catch {
| case e: Throwable => println("error")
| }
error
そこで、Scalaではtry-catch-finally
ではなく、scala.util.Try
を使って例外を捕捉する方法が一般的(?)になっています。
scala.util.Try
は、Javaのtry-catch-finally
と同様に致命的ではないエラー(NonFatalError)しかキャッチしません。
scala> Try(throw new StackOverflowError) recover {
| case e: Throwable => println("error")
| }
java.lang.StackOverflowError
at .$anonfun$res13$1(<console>:13)
at scala.util.Try$.apply(Try.scala:209)
... 38 elided
でも、scala.util.Try
は、例外がスローされた時にはFailure
になってしまい、最後に何かを実行するfinally
のような仕組みはありません。 Scalaでもfinally
したい。そんな時があると思います。
そんな時にはscala.util.control.Exception.ultimately
を使うという手段があります。例外が発生してもしなくても最後に実行する処理を渡すことでfinally
を実現可能です。
scala> Try {
| ultimately {
| println("finally !")
| } {
| println("do something")
| throw new Exception
| println("no execute")
| }
| }
do something
finally !
res: scala.util.Try[Unit] = Failure(java.lang.Exception)
このような書き方であれば、致命的なエラーに関しては無視し、致命的ではないエラーのみを補足することができます。
もちろんfinally
を使う必要がないならultimately
も必要ありません。
参考文献
scala.util.control.Exceptionに関する日本語の記事は2つぐらいしかないです。
- http://seratch.hatenablog.jp/entry/20111126/1322309305
- http://www.mwsoft.jp/programming/scala/scala_try.html
追記
コメントいただきましたが、Scalaのtry-catch-finally
でも、
catch
でNonFatal
を用いてパターンマッチを行うと、致命的ではないものだけを補足できます。