scala.util.control.Exception._を使ったサンプル集
参考
Scala Standard Library 2.9.1.final
/scala/tags/R_2_9_1_final/src/library/scala/util/control/Exception.scala – Scala
Scalaでの例外処理 - Either,Option,util.control.Exception - ( ꒪⌓꒪) ゆるよろ日記
サンプル
以下のサンプルはscala.util.control.Exception._がimportされていることを前提にしています。
import scala.util.control.Exception._
allCatch
val result = try { throw new Exception } catch { case e => }
まず単にallCatchをつけるだけだと何も変わりません。例外はそのままthrowされてしまいます。
val result = allCatch { throw new Exception } // java.lang.Exception
catchして何かするためにはwithApplyにThrowableを受け取って何かする関数を渡します。
allCatch withApply { (t: Throwable) => println("catched") } apply { println("foo") throw new Exception } // foo // catched val catchingEx = allCatch withApply { t => println("catched") } catchingEx { println("foo") throw new Exception } // foo // catched
結果を返す場合はwithApplyに渡す関数で同じ型の結果を返します。
val result: String = allCatch withApply { t => "bar" } apply { "foo" } // "foo" val result: String = allCatch withApply { t => "bar" } apply { throw new Exception } // "bar"
Option型を返す場合は
val result: Option[String] = allCatch withApply { e => None } apply { Some("foo") } // Some("foo") val result: Option[String] = allCatch withApply { e => None } apply { throw new Exception } // None
・・ではなく、Catch#opt(T)でOption[T]を返します。
val result: Option[String] = allCatch opt { "foo" } // Some("foo") val result: Option[String] = allCatch opt { throw new Exception } // None
Catch#either(T)でEither[Throwable, T]を返します。
val result: Either[Throwable, String] = allCatch either { "foo" } // Right(foo) val result: Either[Throwable, String] = allCatch either { throw new Exception } // Left(java.lang.Exception) result match { case Left(t) => println("What's wrong?") // t: Throwable case Right(result) => println(result) // result: String }
finallyの処理は・・
val result = try { throw new Exception } catch { case e => } finally { println("finally") }
andFinallyで追加します。
val result = allCatch withApply { e => } andFinally { println("finally") } apply { "ok" } val exHandler = (t: Throwable) => "ng" val finallyExec = () => println("finally") val result = allCatch withApply exHandler andFinally finallyExec() apply { "ok" }
ignoring
最初の例のように例外を無視する場合はignoringがあります。
val result = try { throw new Exception } catch { case e => }
ignoring(classOf[Throwable]) { throw new Exception }
catching
個別の例外を処理する場合はcatchingに例外クラスを指定します。
val result = try { throw new IllegalArgumentException } catch { case e: IllegalArgumentException => "IAE" case e => throw e } // IAE
val catchingEx: Catch[String] = catching(classOf[IllegalArgumentException]) withApply { t => "IAE" } val result = catchingEx { "ok" } // ok val result = catchingEx { throw new IllegalArgumentException } // "IAE" val result = catchingEx { throw new Exception } // java.lang.Exception
連続パラメータになっているので、複数の例外クラスをまとめることもできます。
val result = try { throw new IllegalArgumentException } catch { case e: IllegalArgumentException => "something wrong" case e: IllegalStateException => "something wrong" case e => throw e } // IAE
val exHandler = (t: Throwable) => "something wrong" val catchingEx = catching(classOf[IllegalArgumentException], classOf[IllegalStateException]) withApply exHandler val result = catchingEx { throw new IllegalArgumentException } // "something wrong" val result = catchingEx { throw new IllegalStateException } // "something wrong"
各例外で違うことをやりたい場合は、それぞれで関数をwithApplyで渡して、orで合成します。
val result = try { throw new IllegalArgumentException } catch { case e: IllegalArgumentException => "IAE" case e: IllegalStateException => "ISE" case e => throw e } // IAE
val catchingIAE = catching(classOf[IllegalArgumentException]) withApply { t => "IAE" } val catchingISE = catching(classOf[IllegalStateException]) withApply { t => "ISE" } val catchingEx = catchingIAE or catchingISE catchingEx { throw new IllegalArgumentException } // "IAE" catchingEx { throw new IllegalStateException } // "ISE" catchingEx { throw new Exception } // java.lang.Exception
catchingPromiscuously
scala.util.control.ControlThrowableとjava.lang.InterruptedExceptionについてはcatchingでは強制的にrethrowされてしまうので、この二つをcatchしたい場合はcatchingPromiscuouslyを使います。
scala> catching(classOf[InterruptedException]) withApply { t => } { throw new InterruptedException } java.lang.InterruptedException at $anonfun$2.apply(<console>:12) at $anonfun$2.apply(<console>:12) at scala.util.control.Exception$Catch.apply(Exception.scala:88) scala> catchingPromiscuously(classOf[InterruptedException]) withApply { t => } { throw new InterruptedException }
handling
withApplyではなくbyで例外時の実行関数を渡します。やっていることはcatchingと同じです。
ソースを読むと内部でcatchingでwithApplyしていることがわかります。
http://lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_9_1_final/src/library/scala/util/control/Exception.scala#L203
val result = try { throw new IllegalArgumentException } catch { case e: IllegalArgumentException => "IAE" case e: IllegalStateException => "ISE" case e => throw e } // IAE
val handlingIAE = handling(classOf[IllegalArgumentException]) by { t => "IAE" } val handlingISE = handling(classOf[IllegalStateException]) by { t => "ISE" } val handlingEx = handlingIAE or handlingISE val result = handlingEx { throw new IllegalArgumentException } // IAE val result = handlingEx { throw new IllegalStateException } // ISE
failing
optと似ていますが、正常系の結果が勝手にSomeにくるまれないので自分でSomeにして返します。
val iaeFailing = failing(classOf[IllegalArgumentException]) val result = iaeFailing { Some("foo") } // Some("foo") val result = iaeFailing { throw new IllegalArgumentException } // None
failAsValue
failAsValueはカリー化された関数で、例外の指定の後にcatchされた後に返す値を名前渡しで指定します。
val iaeFailAsValue = failAsValue(classOf[IllegalArgumentException])("bar") val result = iaeFailAsValue { "foo" } // "foo" val result = iaeFailAsValue { throw new IllegalArgumentException } // "bar"
ultimately
お手軽にfinallyの処理だけ追加したい場合に使えます。例外をcatchする処理は書けません。
try { println("foo") } finally { println("finally") }
val withFinally = ultimately { println("finally") } withFinally { println("foo") } // foo // finally
unwrapping
代わりにThrowable#getCauseして取得した例外を投げます。
unwrapping(classOf[RuntimeException]) { throw new RuntimeException(new IllegalArgumentException) } // java.lang.IllegalArgumentException
ただし、withApplyで指定した関数の引数に渡ってくるのはラップされた例外です。
val catchingEx = unwrapping(classOf[RuntimeException]) withApply { e => e.printStackTrace // java.lang.RuntimeException } catchingEx { throw new RuntimeException(new IllegalArgumentException) }