我有一个 Scala 辅助方法,该方法当前尝试获取 URL 并返回带有该网页 HTML 的 Option[String]。
如果有任何异常(格式错误的 url、读取超时等),或者如果有任何问题,它会返回 None。问题是,最好只抛出异常以便调用代码可以记录异常,还是在这种情况下返回 None 更好?
我有一个 Scala 辅助方法,该方法当前尝试获取 URL 并返回带有该网页 HTML 的 Option[String]。
如果有任何异常(格式错误的 url、读取超时等),或者如果有任何问题,它会返回 None。问题是,最好只抛出异常以便调用代码可以记录异常,还是在这种情况下返回 None 更好?
创建异常的成本很高,因为必须填充堆栈跟踪。抛出和捕获异常也比正常返回更昂贵。考虑到这一点,您可能会问自己以下问题:
您想强制调用者处理错误吗?如果是这样,请不要抛出异常,因为 Scala 没有强制调用者捕获它们的检查异常机制。
如果出现错误,您是否要包含有关失败原因的详细信息?如果没有,你可以直接 return Option[A]
,A
你的返回类型在哪里,然后你要么有Some(validContent)
or None
,没有额外的解释。如果是,您可以返回类似Either[E, A]
Scalaz 的内容Validation[E, A]
。所有这些选项都强制调用者以某种方式解开结果,同时可以随意处理错误E
。现在应该E
是什么?
您想在失败的情况下提供堆栈跟踪吗?如果是这样,您可以返回Either[Exception, A]
或Validation[Exception, A]
。如果你真的去例外,你会想要使用Try[A]
,它的两种可能的情况是Failure(exc: Throwable)
和Success(value: A)
。请注意,您当然会承担创建 throwable 的成本。如果没有,你也许可以直接返回Either[String, A]
(并且要格外小心地记住Right
这里的意思是成功还是失败——Left
通常用于错误,而Right
“正确”的值——Validation
可能更清楚)。如果你想有选择地返回一个堆栈跟踪,你可以使用 Lift's Box[A]
,它可以是Full(validContents)
,Empty
没有额外的解释(非常类似于Option[A]
到这里),或指示Failure
可以存储错误字符串和/或可抛出(以及更多)的。
您是否可能想提供多种指示来说明它失败的原因?然后返回Either[Seq[String], A]
。如果您经常这样做,您可能想要使用 Scalaz 和 aValidation[NonEmptyList[String], A]
来代替,它提供了一些其他不错的东西。查找有关它的更多信息或查看这些用法示例。
我认为在这种情况下,如果记录异常很重要,那么一定要抛出异常(并且可能只返回 String 而不是选项)。否则,您不妨只返回 None。一个警告 - 可能存在您无法预见的其他原因的例外情况,在这种情况下,编写一个包罗万象的代码可能是危险的。
您可以做的一件事是类似于 Lift 的Box
系统。Box 本质上是一个选项,但添加了几个功能:AFull
类似于 a Some
,anEmpty
类似于 a None
,但 Lift 更进一步并具有 a Failure
,类似于 anEmpty
但带有原因/消息。
一般的经验法则是“如果你能处理异常,就处理它”。所以没有足够的上下文来猜测。您可以使用 tryFetchUrl/fetchUrl 方法对。