检查Scala重试控制结构中的多个异常

时间:2013-12-20 09:35:44

标签: scala type-parameter control-structure

我正在尝试开发一个控制结构,该结构会在某些声明的异常上重试,但会抛出其他异常。控制结构很好地工作,但我检查异常是否属于声明的异常类型。在更一般的词汇中,如何检查参数是否是声明的类型参数列表之一?

定义重试控制结构:

def retry[T, R](times:Int=3, delay:Int=1000)(ex:Class[_<:Exception]*)(t:T)(block:T=>R):R = {
try {
  block(t)
}
catch {
  case e:Exception if (isOneOf(e, ex:_*) && times>0) => {
    println(s"Exception $e happened, sleep $delay milliseconds")
    Thread.sleep(delay)
    println(s"$times times remain for retry before give up")
    retry(times-1, delay)(ex:_*)(t)(block)
  }
  case e:Throwable => {
    println(s"Exception $e is not handled")
    throw e
  }
}

}

定义isOneOf函数来检查声明的和运行时异常类型

def isOneOf[T:scala.reflect.ClassTag](obj:T, cs:Class[_]*) = {
  val dc = obj.getClass
  val rc = scala.reflect.classTag[T].runtimeClass
  cs.exists(c=>c.isAssignableFrom(dc) || c.isAssignableFrom(rc))
}

定义一个抛出多个异常的函数

def d(str:String) = {
  val r = Math.random()
  println(r)

  if (r>0.6) throw new IllegalArgumentException
  else if (r>0.4) throw new java.io.IOException
  else if (r>0.2) throw new UnsupportedOperationException
  else println(str)
}

我可以通过重试来调用该函数:

retry(3, 1000)(classOf[IllegalArgumentException], classOf[java.io.IOException])("abc"){
  x=> d(x)
}

我想重试IllegalArgumentException和IOException,但会抛出UnsupportedOperationException。

我的目标是调用这样的函数:

retry(3, 1000)[IllegalArgumentException, java.io.IOException]("abc"){
  x=> d(x)
}

对于重试结构,声明的异常列表在运行时动态传递。所以多个异常案例陈述对我不起作用。捕获异常时,我将其与通用异常匹配,使用isOneOf函数检查异常类型。理想情况下,函数将采用一系列类型,而不是类序列。如何传递一系列异常类型,而不是一系列类,并根据类型序列检查捕获的异常?

1 个答案:

答案 0 :(得分:2)

您如何考虑使用知道哪些异常可以恢复(以及您可以动态构建哪些异常)的函数替换异常列表:

def retry[T, R](times: Int = 3, delay: Int = 1000)(t: T)(block: T => R)(recoverable: Throwable => Boolean): R = {

  Try(block(t)) match {
    case Success(value) => value
    case Failure(throwable) => if (recoverable(throwable)) retry(times - 1, delay)(t)(block)(recoverable) else throw throwable
  }

}

recoverable函数可能如下所示:

def recoverable(throwable: Throwable): Boolean = throwable match {
  case exc @ (_: IllegalArgumentException | _: IOException) => true
  case _ => false
}