考虑一个嵌套结构,其中的相关属性如下:
case class Validation { sql: Option[SqlDataSource] }
case class SqlDataSource { dfh: Option[DataFrameHolder] }
case class DataFrameHolder { sql: Option[String] }
我目前正在使用的天真的方法是:
val ssql = expVal.sql.getOrElse(
vc.dfh.map(_.sql
.getOrElse(throw new IllegalStateException(s"$logMsg CompareDF: Missing sql container"))
).getOrElse(throw new IllegalStateException(s"$logMsg CompareDF: dfh missing sql"))
.sql.getOrElse(throw new IllegalStateException(s"$logMsg CompareDF: Missing sql")))
尽管这样做确实可以完成工作,但它对读者也不友好,对开发人员也不友好(很难正确地嵌套)。有什么更好的方法来解决这个问题吗?
更新谢谢您的出色回答-这将有助于清理并简化向前发展的异常处理代码。
答案 0 :(得分:3)
您可能想使用cats库来使您的代码更具功能性。您可以将Option
转换为Either
,如下所示:
import cats.implicits._
def toEither[T](s: Option[T], error: String) = {
s.liftTo[Either[String, ?]](error)
}
def runEither = {
val result =
for {
sqlDataSource <- toEither(validation.sql, s"Missing sql container")
dataFrameHolder <- toEither(sqlDataSource.dfh, s"dfh missing sql")
sql <- toEither(dataFrameHolder.sql, s"Missing sql")
} yield sql
result match {
case Right(r) => r
case Left(e) => throw new Exception(e)
}
}
答案 1 :(得分:3)
我建议使用与Binzi Cao's answer非常相似的解决方案,但只能将标准库与scala.util.Try
monad一起使用:
def toTry[T](x: Option[T], message: String): Try[T] =
x.map(Success(_)).getOrElse(Failure(new IllegalStateException(message)))
(for {
sqlDataSource <- toTry(validation.sql, s"Missing sql container")
dataFrameHolder <- toTry(sqlDataSource.dfh, s"dfh missing sql")
sql <- toTry(dataFrameHolder.sql, s"Missing sql")
} yield sql)
.get
理解力产生Try
。如果我是.get
,则在产生的Try
上应用Try
会返回String
的内容(dataFrameHolder
中的Success[String]
),或者抛出如果是Failure[IllegalStateException]
,则为例外。
答案 2 :(得分:3)
Luis MiguelMejíaSuárez和Xavier Guihot的回答都很好,但是不需要构建自己的toTry()
方法。 Either
已经提供了一个,并且由于Either
也具有右偏,因此可以用于理解。
import util.Try
val ssql: Try[String] = (for {
ql <- expVal.ql.toRight(new IllegalStateException("yada-yada"))
dfh <- ql.dfh .toRight(new IllegalStateException("yoda-yoda"))
sql <- dfh.sql .toRight(new IllegalStateException("yeah-yeah"))
} yield sql).toTry
答案 3 :(得分:2)
如果您想要快速语义失败,我将for comprehension与j
一起使用。
Try