在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

Monads
Try[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代码。我别无选择。我的问题不是如何毫无例外地做到这一点,我的问题是如何在函数中间返回。您的示例假定函数已完成。我的问题很明确,如果没有例外,还有更多的工作要做。如果抛出异常,如何返回?