[Scala] Future#recoverを使って例外処理する
#scala環境
➜ ~ scala
Welcome to Scala version 2.11.6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_11).
Type in expressions to have them evaluated.
Type :help for more information.
やりたいこと
scala.concurrent.Future
で例外が発生してFailure
になったとき、
- デフォルト値を適用して
Success
で返したい! Failure
のままでいいんだけど別の例外を投げたい!
といったことをしたい。
recoverを使う
そんなときのためのFuture#recover
。
Throwable
をキャッチして新しいFuture
を作ってくれる。
シグネチャは以下。
def recover[U >: T](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Future[U]
ソースはこの辺。
下準備
scala> import scala.concurrent.Future
import scala.concurrent.Future
scala> import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.ExecutionContext.Implicits.global
scala> case class MyException() extends Exception
defined class MyException
サンプル
// まずはそのまま実行してみる
scala> Future {
| throw new IllegalArgumentException()
| }
res0: scala.concurrent.Future[Nothing] = scala.concurrent.impl.Promise$DefaultPromise@b59d31
scala> res0.value.get
res1: scala.util.Try[Nothing] = Failure(java.lang.IllegalArgumentException)
// デフォルト値を適用したい!
scala> Future {
| throw new IllegalArgumentException()
| } recover {
| case e: IllegalArgumentException => 0
| }
res2: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@2e1d27ba
scala> res2.value.get
res3: scala.util.Try[Int] = Success(0)
// 別の例外を投げたい!
scala> Future {
| throw new IllegalArgumentException()
| } recover {
| case e: IllegalArgumentException => throw MyException()
| }
res4: scala.concurrent.Future[Nothing] = scala.concurrent.impl.Promise$DefaultPromise@3bcd05cb
scala> res4.value.get
res5: scala.util.Try[Nothing] = Failure(MyException)
// Successなときはそのままの結果
scala> Future {
| 10
| } recover {
| case e: IllegalArgumentException => throw MyException()
| }
res6: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@56928307
scala> res6.value.get
res7: scala.util.Try[Int] = Success(10)
recoverWithを使う
Future#recoverWith
なんていうのもある。
Future#recover
とは部分関数の型が違って、Throwable
を受け取ってFuture
を返すようになる。
シグネチャは以下。
def recoverWith[U >: T](pf: PartialFunction[Throwable, Future[U]])(implicit executor: ExecutionContext): Future[U]
ソースはこの辺。
サンプル
// デフォルト値を適用したい!
scala> Future {
| throw new IllegalArgumentException()
| } recoverWith {
| case e: IllegalArgumentException => Future.successful(0)
| }
res8: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@463b4ac8
scala> res8.value.get
res9: scala.util.Try[Int] = Success(0)
// 別の例外を投げたい!
// これは特に変わらず
scala> Future {
| throw new IllegalArgumentException()
| } recover {
| case e: IllegalArgumentException => throw MyException()
| }
res10: scala.concurrent.Future[Nothing] = scala.concurrent.impl.Promise$DefaultPromise@4a3e3e8b
scala> res10.value.get
res11: scala.util.Try[Nothing] = Failure(MyException)
// Successなときはそのままの結果
scala> Future {
| 10
| } recoverWith {
| case e: IllegalArgumentException => Future.successful(0)
| }
res12: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@6a1ebcff
scala> res12.value.get
res13: scala.util.Try[Int] = Success(10)