从Scala中的异常返回的正确方法是什么?

时间:2014-08-19 23:55:22

标签: 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 return false
  )
}

// do more stuff

true

我该如何正确地做到这一点?当然,我不想使用“return”语句,但我也不想通过“做更多的东西”并最终返回true。

5 个答案:

答案 0 :(得分:11)

您希望表示可以成功或发出错误信号的计算。这是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转换为Option

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
}

虽然我建议返回比Boolean更有意义的东西,只要它有意义。

当然这可以嵌套

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
     }
}

但您应该考虑将Try块放入单独的函数中(返回Try)。

最终,我们可以利用Try是一个monad的事实,并做这样的事情

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
}

答案 1 :(得分:3)

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

HTH。小功能有帮助。

另一个提示:

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

答案 2 :(得分:1)

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来获得更干净,功能更强大的代码 请参阅https://codereview.stackexchange.com/questions/38689/code-with-many-early-returns-exits-into-the-functional-style

我遇到了类似你的问题,但 Stackexchange CodeReview 中的答案对我帮助很大。

答案 3 :(得分:0)

成功或错误的案例可以用几种Scala类型表示。

如果您认为&#34意义上的错误,则缺少某些内容" (例如,找不到文件),您可以使用Option[T](例如Option[File]),案例值为NoneSome(T)。然后可以使用orElsegetOrElsefoldmap / flatMap函数来发送。

您还可以Either[E, T]使用(按惯例)Left(E)案例中的错误值(例如String作为错误消息),并在Right(T)成功T值。

可以以相同的方式使用Monads Try[T]Future[T]

在I / O领域,非常好的scala-arm lib提供类型ManagedResource[T],它包含基于成功(T)或错误(List[Throwable]])计算结果资源。

Scalaz中的评估类型对这种情况也很有用。

答案 4 :(得分:-1)

' util.Try {做一些东西} .isSuccess'