我知道Try / Success / Failure与Try Catch之间存在差异。官方文件也有一个很好的例子:
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 <------------ Here!
}
}
但是,我很难理解
以上示例中显示的Try的一个重要属性是它的能力 管道,链,操作,沿途捕捉异常。 上面的例子中的flatMap和map组合器各自基本上 将他们成功完成的价值,包裹在其中 成功类型由下一个组合器进一步操作 在链中,或者通常包含在Failure类型中的异常 简单地传递给链条。组合如恢复和 recoverWith旨在提供某种类型的默认行为 失败的情况。
是否有任何示例来说明如何使管道,连锁,运营更容易......&#34;?任何例子来说明为什么我们没有try-catch的相同好处?
另外,为什么我们会在divide
中返回Failure
?否则,我们会type mismatch
?这是唯一的原因吗?
答案 0 :(得分:5)
<强> Try[A]
强>
这是一个由2个案例组成的代数数据类型(ADT):Success[A]
和Failure[A]
。这个代数结构定义了许多操作,如map
,flatMap
等。 Try
有一个map
和一个flatMap
以及一个A
到Try[A]
的构造函数,这个结构就是Monad。
Monads是抽象,允许我们以功能方式表达计算序列。我们来看一个例子
def tryDivide(v1: Double, v2: Double): Try[Double] = Try(v1 / v2)
val tryDivisions = tryDivide(1.0, 2.0).flatMap {
res => tryDivide(res, 2)
}.flatMap {
res => tryDivide(res, 0)
}
作为此代码的结果,我们将获得Failure[A]
,因为最新的操作除以零。 Try是Monad的事实允许我们使用像这样的理解来重写它
for {
v1 <- tryDivide(1.0, 2.0)
v2 <- tryDivide(v1, 2)
res <- tryDivide(v2, 0)
} yield res
<强> try
强>
另一方面,try
只是一种语言语法,它允许您捕获可能从代码中抛出的异常,但它不是具有可以执行的方法的代数结构。
答案 1 :(得分:1)
Try[A]
表示一个计算,如果它成功的是A
类型的值,否则出现错误并且是Throwable
。它有两种形式:在成功的计算中,它是A
类型的值,包装为Success[A]
的实例。在失败时,它是Failure[A]
的实例,它包含Throwable
例外。
Try
的一个特点是它允许您以非常智能的方式使用高阶函数(如Option
,Either
和其他monad)和链操作。 / p>
让我们说你有这个小程序:
scala> def divide(x: Int, y: Int): Try[Int] =
if (y == 0) Try(throw new Exception("Error: division by zero!"))
else Try(x / y)
divide: (x: Int, y: Int)scala.util.Try[Int]
你得到了
scala> divide(3,2)
res30: scala.util.Try[Int] = Success(1)
和
scala> divide(3,0)
res31: scala.util.Try[Int] = Failure(java.lang.Exception: Error: division by zero!)
因此,您可以使用高阶函数的功能同样以优雅的方式捕获故障:
scala> divide(3,0).getOrElse(0)
res32: Int = 0
这只是一个例子,但想想你是否尝试执行一个可能失败的更复杂的计算,你必须捕获这个结果并采取相应的行动。
为什么不在Scala中使用try catchs
?这不是因为你无法做到这一点,而是因为它不是很有用。如果你需要处理另一个线程中发生的异常(比如演员),你就不能捕获该异常,你可能想要将消息传递给当前的主线程,说明计算失败了,你将弄清楚如何处理。
另外,为什么我们在失败中回归分裂?否则,我们会出现类型不匹配的情况?这是唯一的原因吗?
它会在divide
中返回Failure
,因为如果程序失败,它会让您重新运行程序,但这只是程序员做出的决定。您可能只是返回Failure
包装某种错误消息。
答案 2 :(得分:0)
首先关于flatMap()的一些背景:这个函数在很多方面指的是monadic&gt; =(bind)运算符的众所周知的概念,如果你想更深入地了解它我强烈建议你阅读这本书& #34;为了大好而学习你的Haskell!&#34;。
但是简单地使用Try就可以做到这样的事情:
someTry.flatMap(//doSomething1).flatMap(//doSomething2)
然后进行一些匹配以从第一个或第二个函数获取值或获取错误(请注意,任何来自错误的flatMap都不会被计算出来并且错误将保持不变)但是你会用旧的方式做像这样的人:
try{
//doSomething()
} catch {
...
}
try {
//domSomething2()
} catch {
...
}