scala中的异常处理

时间:2014-12-27 06:12:28

标签: scala exception-handling either

我正在使用Scala处理应用程序。我试图在应用程序中实现异常处理。我尝试使用Either来处理异常。对于简单的情况,似乎足以处理异常。但是,当我需要通过连接从多个表中获取结果时,异常处理产生的问题多于解决问题。我的申请结构如下:

将存储库模式用于定义所有数据库交互操作的数据库操作。例如,我有一个中央存储库,用于定义findAllfindByIdinsertdeleteupdateexists等我的{{ 1}}方法签名已更改为findAll,类似Either[CustomException, List[TEntity]]方法类型为findById

现在假设,如果我需要在我的方法中从数据库中获取员工,我将做如下的事情:

Either[CustomException, Option[TEntity]]

现在,车辆类型为def getVehicleById(id:Long) = { val vehicle = repository.findById(id) //i have one-to-one mapping with Employee table for the driver of the vehicle val driver = empRepository.findById(vehicle.driverId) } ,驾驶员类型为Either[CustomException, Option[Vehicle]]

如果我在获得结果后需要再做任何操作,我必须使用右/左案例然后再这样做。问题是,可能在Right的情况下,我可能需要与另一个表连接,这使得结果再次成为Either[CustomException, Employee]。如果在该操作中发生任何错误,我需要再次使用try catch块。 我觉得当代码复杂性增加时,这种处理变得非常难以管理,而且我将有很多锅炉板代码来处理这些情况,这违反了Scala原则本身。

所以我的问题是,如何在没有太多锅炉板代码的情况下以更好的方式处理异常。

注意:我来自Java背景,现在只在Scala工作了几个月。

修改

使用Try添加示例代码: 这个样本非常接近我的要求。

Either[CustomException, Entity]

但是使用bove代码,我收到了编译错误。

import scala.util._
def checkTry:Try[List[Int]] = Success(List(2))
def checkTryStr:Try[String] = Success("Asd")

def getVehicleWithDriver = for {
  a <- checkTry
  c <- a
  b <- checkTryStr
}yield {
  (c,b)
}
getVehicleWithDriver

3 个答案:

答案 0 :(得分:2)

您想使用for / yield糖。您可以养成将.right放在所有Either上的习惯,或者@Gangstead建议使用Scalaz中的\/。 (Scalaz当然有可怕的部分 - 我已经使用它4年了,我仍然被Strength吓倒了 - 但是从简单的部分开始并以你的方式工作是完全可能的向上)。

for {
  vehicle <- repository.findById(id).right
  driver <- empRepository.findById(vehicle.driverId).right
  somethingElse <- somePossiblyFailingComputation.right
} yield somethingElse
//Don't need the .right if you're using Scalaz \/

其他重要提示:当您想要将有效功能应用于List时,您希望使用Scalaz traverse

vehicleList <- vehicleIdList.traverse(repository.findById) //assuming you're using \/
//might need a few .right if you're using Either

当您调用可能引发异常的Java代码时,请使用scala.util.control.Exception&#39; s catching

val myEither = catching(classOf[SomeException]) either someJavaMethodThatThrows()
// (...).disjunction if you're using \/.

如果您需要使用另一种有效的背景&#34;在使用Either / \/的同时,您必须开始查看 monad变形金刚,但最好只使用{{ {1}}首先。

希望有所帮助;祝你好运,希望你喜欢斯卡拉。

答案 1 :(得分:1)

看看Scalaz的分离\/

警告:Scalaz是由铁杆人写的硬核scala。

看看Brendon McAdams(@Rit)关于"Scalaz' Gateway Drugs"的演讲。对于来自Java的程序员来说,他更加平易近人,而且他非常实用

答案 2 :(得分:0)

您想使用Try,而不是Either。它是一个monad,因此您可以mapflatMap,或者在for理解中使用它。它看起来很优雅。

def getVehicleWithDriver(id: String): Try [(Vehicle, Driver)] = for {
    vehicle <- repository. findById(id)
    driver <- empRepository.findById(vehicle.driverId)
} yield {
    (vehicle, driver)
}