【问题标题】:Scala: idiomatic Try-match and avoiding catching ThrowableScala:惯用的 Try-match 和避免捕获 Throwable
【发布时间】:2018-03-27 22:50:52
【问题描述】:

在 Scala 中,将模式匹配用于异常处理的典型用法(至少对于像 thisthis 这样的来源而言)如下所示:

Try(...) match {
  case Success(_) => println("success")
  case Failure(exc) => println(s"caught: $exc")
}

但是,该模式也可以捕获try 块中抛出的任何非Exception Throwables:

Try(throw new AssertionError("assertion error")) match {
  case Success(_) => println("success")
  case Failure(exc) => println(s"caught: $exc")
}

caught: java.lang.AssertionError: assertion error

至少在 Java 中,在没有令人信服的理由的情况下捕获 Throwable 通常被认为是一种反模式。 (This source 为 Scala 提供了同样的建议。)

避免静默捕捉Throwable 的一种选择是捕捉它并重新抛出它:

Try(throw new AssertionError("assertion error")) match {
  case Success(_) => println("success")
  case Failure(exc : Exception) => println(s"caught: $exc")
  case Failure(th) => throw th
}

不过,为了避免捕获非ExceptionThrowables(通常被认为是不可恢复的),并且让这样的Throwables 逃逸,这似乎很奇怪,这在 Java 风格中是隐含的try/catch 语法,必须显式实现。

是否有更简洁/惯用的语法在 Scala 中使用模式匹配进行异常处理,同时避免无意中捕获 Throwable

【问题讨论】:

  • FWIW,Try 仅捕获 NonFatal 可投掷物。
  • @hoyland 有趣的点;如果我最初的问题的答案是“否”(不存在这样的惯用语法),也许这可以解释原因:设计者认为避免捕获Throwable 并不重要,因为他们已经区分了致命与非致命Throwables 通过NonFatal 提取器。 (尽管在这种情况下,“致命”Throwables 的集合似乎是不可扩展的,这似乎很不幸。)

标签: scala exception-handling throwable


【解决方案1】:

因为recover() 方法采用PartialFunction,所以它可用于过滤您要处理的Throwable 的类型。之后,您可以让get 解包Try 并检索一个值,如果它是Success 或已处理的Failure,或者如果它仍然是Failure,它将重新抛出,即未处理recover().

val result = Try{
               //code block here
             }.recover{
               case exc:Exception => ... //should return same type as Success
             }.get //unwrap the Try, will throw if Throwable was not an Exception

【讨论】:

  • 有趣的方法,但它似乎迫使使用另一种不受欢迎的做法,调用Option.get (alvinalexander.com/scala/…)。有没有办法不用调用get也能达到同样的效果? getOrElse(throw ...) 似乎失去了原来的 Throwable
  • 不鼓励get 的原因是因为如果你尝试get 错误的东西(Option.None 或未处理的Try.Failure),它会抛出,但这就是你问的对于get 将为您重新投掷,因此您不必这样做。
猜你喜欢
  • 2017-11-04
  • 1970-01-01
  • 2020-03-27
  • 1970-01-01
  • 1970-01-01
  • 2013-07-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多