scala.util.Try比try..catch有什么优势?

时间:2016-11-28 05:04:30

标签: scala try-catch monads codacy

在线搜索答案会给出两个重要的帖子(Codacy'sDaniel Westheide's),两者都给出与Scala's official documentation for Try相同的答案:

  

上面示例中显示的Try的一个重要属性是它能够管理或链接操作,并在此过程中捕获异常。

上面引用的例子是:

import scala.io.StdIn
import scala.util.{Try, Success, Failure}

def divide: Try[Int] = {
  val dividend = Try(StdIn.readLine("Enter an Int that you'd like to divide:\n").toInt)
  val divisor = Try(StdIn.readLine("Enter an Int that you'd like to divide by:\n").toInt)
  val problem = dividend.flatMap(x => divisor.map(y => x/y))
  problem match {
    case Success(v) =>
      println("Result of " + dividend.get + "/"+ divisor.get +" is: " + v)
      Success(v)
    case Failure(e) =>
      println("You must've divided by zero or entered something that's not an Int. Try again!")
      println("Info from the exception: " + e.getMessage)
      divide
  }
}

但我可以使用传统的try块轻松管道操作:

def divideConventional: Int = try {
  val dividend = StdIn.readLine("Enter an Int that you'd like to divide:\n").toInt
  val divisor = StdIn.readLine("Enter an Int that you'd like to divide by:\n").toInt
  val problem = dividend / divisor
  println("Result of " + dividend + "/"+ divisor +" is: " + problem)
  problem
} catch {
  case (e: Throwable) =>
    println("You must've divided by zero or entered something that's not an Int. Try again!")
    println("Info from the exception: " + e.getMessage)
    divideConventional
}

(注意:dividedivideConventional的行为略有不同,因为后者在出现问题的第一个错误时出错,但就是这样。尝试输入“10a”作为{{1的输入看看我的意思。)

我试图看到dividend的流水线优势,但对我而言,似乎这两种方法是相同的。我错过了什么?

1 个答案:

答案 0 :(得分:6)

我认为你很难看到Try[T]的构图能力,因为你在两种情况下都在本地处理异常。如果您想通过其他操作撰写divideConventional该怎么办?

我们有一些喜欢:

def weNeedAnInt(i: Int) = i + 42

然后我们会有:

weNeedAnInt(divideConventional())

但是,让我们说你想要最大化你允许用户输入的重试次数(这通常是你在现实场景中所拥有的,你可以永远重新输入一个方法?我们必须另外用weNeedAnInt包裹try-catch本身的调用:

try {
  weNeedAnInt(divideConventional())
} catch {
   case NonFatal(e) => // Handle?
}

但是,如果我们使用divide,并且让我们说它没有在本地处理异常并向外传播内部异常:

def yetMoreIntsNeeded(i: Int) = i + 64

val result = divide.map(weNeedAnInt).map(yetMoreIntsNeeded) match {
  case Failure(e) => -1
  case Success(myInt) => myInt
}

println(s"Final output was: $result")

这不简单吗?也许,我认为这有一些主观性的答案,我发现它更清洁。想象一下,我们有很长时间的这种操作,我们可以将每个Try[T]组合到下一个,并且只在管道完成时担心问题。