Scala异常:缺少captureWithRethrow?建议需要

时间:2015-05-26 11:47:39

标签: scala exception

在scala.util.control.Exception中,有很多函数可以创建捕获器等。但是,在某些情况下,我发现我想翻译/重命名/包装这样的异常:

class MyBaseException...
class MyDerivedException extends MyBaseException ...
class MyOtherDerivedException extends MyBaseException ...

try {
    // some code throw new MyDerivedException
    // some other code throw new java.lang.IllegalArgumentException
} catch {
    case e: MyBaseException => throw e  // Let every exceptions derived from MyBaseException go through unchanged
    case NonFatal(e) => new MyOtherDerivedException(e)
}

这也可以通过以下方式完成:

try{ ... } catch {
    case NonFatal(e) if (!classOf[MyBaseException].isAssignableFrom(e.getClass)) => new MyOtherDerivedException(e)
}

所以现在,将其纳入scala.util.control.Exception捕获语法,我没有找到任何方法。在实践中,我想要这样的东西:

def wouldMatch(x: Throwable, classes: scala.collection.Seq[Class[_]]): Boolean =
  classes exists (_ isAssignableFrom x.getClass)

def shouldRethrowIfMatchOrElse(x: Throwable, classes: scala.collection.Seq[Class[_]]): Boolean = {
  if (wouldMatch(x, classes)) true
  else shouldRethrow(x)
}

def catchingWithRethrow[T](c: Catcher[T])(exceptions: Class[_]*): Catch[T] = new Catch(c, None, { shouldRethrowIfMatchOrElse(_, exceptions) })

可以这样使用:

val myCatching = catchingWithRethrow(nonFatalCatcher)(classOf[MyBaseException]).withApply(e => new MyOtherDerivedException(e))
myCatching {
  // some code throw new MyDerivedException
  // some other code throw new java.lang.IllegalArgumentException
}

我发现Catch [T]应该有一个withRethrow(...)函数来覆盖第三个参数。这可能会更加优雅:

val myCatching = catching(nonFatalCatcher).withRethrow(...).withApply(e => new MyOtherDerivedException(e))

我是否遗漏了scala.util.control.Exception中没有自定义代码可以实现的内容?

您对此有何看法?

2 个答案:

答案 0 :(得分:2)

  

我发现Catch [T]应该有一个withRethrow(...)函数来覆盖第三个参数。 [...]我是否在scala.util.control.Exception中遗漏了一些可以在没有自定义代码的情况下实现这一目标的内容?

标准库中可能有类似withRethrow的内容,但我也没有看到它。幸运的是,Scala允许我们使用隐式类来丰富现有接口。假设您不介意添加三行自定义代码,您可以实现所需的语法:

implicit class WithRethrow[T](theCatch: Catch[T]) {
  def withRethrow(exceptions: Class[_]*): Catch[T] = new Catch[T](theCatch.pf, theCatch.fin, t => exceptions exists (_.isAssignableFrom(t.getClass)))
}

使用您的用例

// may need to import the implicit class if it is not already in scope
val myCatching = catching(nonFatalCatcher).withRethrow(classOf[MyBaseException]).withApply(e => throw new MyOtherDerivedException(e))
myCatching {
  throw new OutOfMemoryError()        // OutOfMemoryError is thrown because it is not non-fatal
  throw new IllegalArgumentException  // MyOtherDerivedException is thrown because IllegalArgumentException is not rethrown
  throw new MyDerivedException        // MyDerivedException is thrown because MyDerivedException is rethrown
}

答案 1 :(得分:-1)

这似乎是一个非常专业/不寻常的用例。它违反了LSP。并且使用异常在scala中是单一的 - scala.util.control.Exception主要是捕获库函数可能抛出的异常并将它们转换为更多惯用的潜在失败表达式。

如果你想这样做,那么为它编写自己的代码 - 它应该非常简单。我真的不认为这是一个常见的用例,因为它有一个标准的库函数。