LoginSignup
9
5

More than 5 years have passed since last update.

Scalaのscala.util.TryでJavaのtry-catch-finallyを表現する

Last updated at Posted at 2018-09-07

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つぐらいしかないです。

追記

コメントいただきましたが、Scalaのtry-catch-finallyでも、
catchNonFatalを用いてパターンマッチを行うと、致命的ではないものだけを補足できます。

NonFatalの例外 - scala_text

9
5
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
5