我认为从 Java 的异常概念开始会有所帮助。如果调用 Java 方法,那么它基本上是做某事(返回值或引起副作用)的契约。该方法做出某些假设(例如,操作系统将配合读取文件的请求)。有时,如果不满足这些条件,它会返回一个空值,有时它会完全停止执行并“抛出异常”。
这可能是个问题,因为 Java 方法的契约并不总是清晰的。声明返回类型 String 的 Java 方法实际上具有三种结果:String 值、null 或异常。异常的一个问题是它们会停止代码的执行,可能会掩盖方法中的其他问题,或者可能无法关闭打开的资源(这是 的原因try, catch, finally
)
Scala 寻求关于返回类型的清晰性。一种方法是收集方法中发生的所有异常,然后将该异常列表作为返回值传递。但是,我们需要有一个返回类型,表示“我们将返回一些东西,或者我们可能什么也不返回”(scala.Option),或者也许,“我们将返回预期的答案或者我们”将返回有关未返回预期答案的原因的信息”(scala.util.Either),或者可能是“我们将尝试进行有风险的操作,这可能会导致成功或失败。” ( scala.util.Try )
Scala 使用 Option 处理空值的可能性。Option 是具有两个子类的类:None
and Some
,它是一个只包含一个元素的容器。例如:
val contacts = Map("mark" -> 1235551212, "john" -> 2345551212, "william" -> 3455551212)
val phoneOfJohn: Option[Int] = contacts.get("john")
val phoneOfAlex: Option[Int] = contacts.get("alex")
phoneOfJohn match {
case Some(number) => callPhone(number)
case None => Logger.debug("unable to call John, can't find him in contacts")
}
phoneOfAlex match {
case Some(number) => callPhone(number)
case None => Logger.debug("unable to call Alex, can't find him in contacts")
}
这个代码给 John 打了一个电话,它会记录下它无法呼叫 Alex 的事实,因为它在电话簿中找不到他的电话号码。但是 anOption
没有提供关于为什么没有返回值的信息。如果我们想收集这些原因,我们可以使用Either
. 有Either
两个子类: ALeft
可以存储在执行“风险操作”过程中收集的所有异常,而 aRight
将类似于 aSome
并包含预期值。
对 Either进行折叠操作以将其转换为 Left 或 Right 有点违反直觉,因此我们来到 scala.util.Try。
@marius是 Twitter 的 scala 开发人员,他写了一篇非常好的文章,介绍了采用scala.util.Try的理由。我想这就是你要找的。
scala.util.Try 的本质是一个有风险的操作可能会导致Success
or Failure
。在 scala.util.Try 之前,开发人员会使用 Option 或 Either。如果您从文件中执行缓冲读取器,则如下所示:
import scala.util.{Try, Failure, Success}
def foo(fileName: String): Try[String] = Try {
scala.io.Source.fromFile(fileName).bufferedReader().readLine()
}
def bar(file: String): Unit = foo(file) match {
case Success(answer) => Logger.info(s"$file says the answer is $answer")
case Failure(e) => Logger.error(s"couldn't get answer, errors: ${e.getStackTrace}")
}
bar("answer.txt") \\ will log the answer or a stack trace
希望这可以帮助!