在Scala中,从异常返回的正确方法是什么?
在非函数式语言中,我可能会执行以下操作:在Scala中,从异常返回的正确方法是什么?,scala,Scala,在非函数式语言中,我可能会执行以下操作: try { // some stuff } catch Exception ex { return false; } // Do more stuff return true; 然而,在Scala中,这种模式显然是不正确的。如果我的scala代码如下所示: try { // do some stuff } catch { case e: Exception => // I want to get out of here and
try {
// some stuff
} catch Exception ex {
return false;
}
// Do more stuff
return true;
然而,在Scala中,这种模式显然是不正确的。如果我的scala代码如下所示:
try {
// do some stuff
}
catch {
case e: Exception => // I want to get out of here and return false
)
}
// do more stuff
true
我该如何正确地做到这一点?当然,我不想使用“return”语句,但我也不想通过“做更多事情”最终返回true
scala> def f() = try { ??? ; 1 } catch { case _: Throwable => 2 }
f: ()Int
scala> f()
res2: Int = 2
scala> import util._
import util._
scala> def g() = Try { ??? ; 1 } recover { case _ => 2 } get
warning: there was one feature warning; re-run with -feature for details
g: ()Int
scala> g()
res3: Int = 2
嗯。小功能有帮助
另一个提示:
scala> def j() = Try (1) map (_ + 42) recover { case _ => 2 } get
warning: there was one feature warning; re-run with -feature for details
j: ()Int
scala> j()
res4: Int = 43
'util.Try{do some stuff}.issucess'
Try catch
表达式不适合函数式编程
无论如何,一个简单的解决方案仍然使用try catch
:
val result = try {
// do some stuff
Some(/* The final expression */)
}
catch {
case e: Exception => // Do something or nothing
None
}
result match {
case Some(r) => // Do something with r
true
case None => false
}
您可以使用scala.util.Try
来获得更干净、更具功能性的样式化代码。指
我和您一样也遇到过类似的问题,但Stackexchange CodeReview中的答案对我帮助很大。成功或错误的案例可以用几个Scala类型来表示
如果您认为“缺失”(例如文件未找到)的错误,则可以使用<代码>选项[t] < /代码>(例如<代码>选项[文件] < /COD>),用例值<代码>无< /代码>或<代码>某些(t)< /代码>。然后可以使用
orElse
、getOrElse
或fold
和map
/flatMap
函数来分派案例
您还可以使用或[E,T]
,按照惯例,在左侧(E)
案例中使用错误值(例如,一个字符串作为错误消息),在右侧(T)
中使用成功的T
值
MonadsTry[T]
或Future[T]
也可以以同样的方式使用
在I/O领域,非常好的scala arm库提供了类型ManagedResource[T]
,它包装了基于资源的成功(T
)或错误(List[Throwable]]
)计算结果
Scalaz中的值类型对于此类情况也很有用。您希望表示一个计算,该计算可以成功,也可以发出错误发生的信号。这是Try
monad的完美用例
import scala.util.{ Try, Success, Failure }
def myMethod: Try[Something] = Try {
// do stuff
// do more stuff
// if any exception occurs here, it gets wrapped into a Failure(e)
}
因此,您返回的是一个Try
,而不是一个Bool
,它更加清晰和惯用
用法示例:
myMethod match {
case Success(x) => println(s"computation succeded with result $x")
case Failure(e) => println(s"computation failed with exception $e.getMessage")
}
如果您甚至不关心异常,但只想在成功时返回一个值,您甚至可以将Try
转换为选项
def myMethod: Option[Something] = Try {
// do stuff
// do more stuff
// return something
// if any exception occurs here, it gets wrapped into a Failure(e)
}.toOption
myMethod match {
case Some(x) => println(s"computation succeded with result $x")
case None => println("computation failed")
}
要回答评论中的问题,您可以
Try {
// do stuff
} match {
case Failure(_) => false
case Success(_) =>
// do more stuff
// true
}
尽管我建议在有意义的时候返回比布尔值更有意义的内容
当然,这可以嵌套
Try {
// do stuff
} match {
case Failure(_) => false
case Success(_) =>
// do more stuff
Try {
// something that can throw
} match {
case Failure(_) => false
case Success(_) =>
// do more stuff
true
}
}
但您应该考虑将<代码>尝试块到单独的函数中(返回<代码>尝试< /代码>)。< /P>
最终,我们可以利用
Try
是一个单子的事实,这样做
Try { /* java code */ }.flatMap { _ =>
// do more stuff
Try { /* java code */ }.flatMap { _ =>
// do more stuff
Try { /* java code */ }
}
} match {
case Failure(_) => false // in case any of the Try blocks has thrown an Exception
case Success(_) => true // everything went smooth
}
我认为这是一个糟糕的模式。我会在try
中添加“do more stuff”,而catch
是最后一段代码。如果我这样做,我就可以在try块中抛出任意一个异常,并且很难区分它们。更糟糕的是,请参阅文档中的用法,类似地,然后是Salasz解决方案。当然,但这不是我的问题——当故障发生时,在函数的中间如何返回?我想继续在函数中做更多的工作,如果一切正常,但如果中间有故障,就返回。只需在代码中包装失败的代码>尝试< /COD>并检查它的结果。看看我的最新消息。也许我误解了。这就是我的代码现在所做的。您的示例假定try块是函数中的最后一个。事实并非如此。如果try块没有失败,还有很多事情要做。我需要知道的是,如果try块失败,该怎么办。函数中有多个地方需要调用Java代码,这些代码可能引发异常。我需要捕获该异常,执行一些操作,然后返回false。如果它抛出异常,则捕获它,记录它,并返回false。如果没有引发异常,请调用另一个方法。如果它抛出异常,则捕获它,记录它,并返回false。如果没有引发异常,请对六个或七个方法调用重复此操作。如果到达结尾,请返回true。不客气,不要忘了检查提供的语法糖以获得理解,这可以使monad合成更加清晰。我正在调用引发异常的Java代码。我别无选择。我的问题不是如何毫无例外地做到这一点,我的问题是如何在函数中间返回。您的示例假定函数已完成。我的问题很明确,如果没有例外,还有更多的工作要做。如果抛出异常,如何返回?