Scala最优雅的方式来处理选项并从Scala Map中引发异常 [英] Scala most elegant way to handle option and throw exception from Scala Map
问题描述
我有一张地图,想要:
- 无需处理Option即可获取值
- 在没有这样的密钥时记录一条消息.
- 在不存在密钥时,返回默认值(除了记录消息外)也很不错.这是可选的,因为当代码在此处失败时,就不应继续下去.
我有几种方法
val map: Map[String, Int] // defined as such for simplification
// 1 short but confusing with error handling
def getValue(key: String): Int = {
map.getOrElse(key, scala.sys.error(s"No key '$key' found"))
}
// in case you don't know scala.sys.error
package object sys {
def error(message: String): Nothing = throw new RuntimeException(message)
}
// 2 verbose
def getValue(key: String): Int = {
try {
map(key)
} catch {
case _: Throwable => scala.sys.error(s"No key '$key' found")
}
}
// 3 Try and pattern matching
import scala.util.{Failure, Success, Try}
def getValue(key: String): Int = {
Try(map(key)) match{
case Success(value) => value
case Failure(ex) => sys.error(s"No key '$key' found ${ex.getMessage}")
}
}
欢迎使用其他解决方案.我正在寻找简洁而不神秘的东西.使用标准scala(无需Scalaz,Shapeless ...)
Others solutions are welcomed. I'm looking for conciseness without being cryptic. Using standard scala ( no need for Scalaz, Shapeless ... )
灵感:
- https://alvinalexander.com/scala/how-to-access-map-values-getorelse-scala-cookbook
- http://danielwestheide.com/blog/2012/12/26/the-neophytes-guide-to-scala-part-6-error-handling-with-try.html
推荐答案
引发错误的最优雅方法是您的(1):
map.getOrElse(键,抛出/*一些异常*/)
不应使用2nd和3rd选项:您知道可能发生的实际错误:地图不包含键.因此,将其包装在try(或Try)中是多余的工作.更糟糕的是,它将捕获到其他本来不是的例外.特别是不应捕获的致命异常.
The 2nd and 3rd options should not be used: You know which actual error can happen: the map doesn't contain the key. So wrapping it in a try, or Try, is more work than necessary. And worst, it will catch other exceptions that are not meant to be. In particular Fatal exception that should not be caught.
但是,在Scala中管理异常的最优雅的方法是实际跟踪类型.
But, the real most elegant way to manage exceptions in scala is to actually track them with types.
一种简单的通用方法(但有时也通用)是使用Try.一旦您的代码可能失败,一切都将包裹在Try中,以后的代码将在map和flatMap中调用(您可以使用for-comprehension使其更具可读性)
A simple generic way (but sometime too generic) is to use Try. As soon as your code might fail, everything is wrapped in Try and later code is called in map and flatMap (you can use for-comprehension to make it more readable)
一种更具体的方法是使用scalaz中的Escaler或scalaz中的 \/
并显式管理错误的类型,例如 \/(MissingData,String)
来创建您的某些 MissingData
类.例如:
A more specific way is to use Either (from scala) or \/
from scalaz and explicit the type of error you are managing, such as \/(MissingData, String)
for some MissingData
class you've made. Eg:
import scalaz.\/
import scalaz.syntax.either._
sealed trait KnownException
case class MissingData(message: String) extends KnownException
// type alias used for readability
type Result[A] = \/[KnownException, A]
// retrieve a param, or a MissingData instance
def getParam(param: Map[String, Int], key: String): Result[Int] = param.get(key) match {
case None => MissingData(s"no param for key $key").left
case Some(v) => v.right
}
// example on how to combine multiple \/
// using for-comprehension
def computeAPlusB(param: Map[String, Int]): Result[Int] = for {
paramA <- getParam(param, "a")
paramB <- getParam(param, "b")
} yield paramA + paramB
这篇关于Scala最优雅的方式来处理选项并从Scala Map中引发异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!