[英]Exception handling in scala
I am working on an application with Scala. 我正在使用Scala处理应用程序。 I am trying to implement Exception Handling in the application.
我试图在应用程序中实现异常处理。 I tried using
Either
for handling the exceptions. 我尝试使用
Either
来处理异常。 For simple cases, it seems to be enough to handle exceptions. 对于简单的情况,似乎足以处理异常。 However, when I need to get results from multiple tables by joins, the exception handling is creating more issues than solving.
但是,当我需要通过连接从多个表中获取结果时,异常处理产生的问题多于解决问题。 My application structure is explained below:
我的应用程序结构解释如下:
Using repository pattern for the database operations which defines all the database interaction operations. 将存储库模式用于定义所有数据库交互操作的数据库操作。 For eg, I have a central repository which defines
findAll
, findById
, insert
, delete
, update
, exists
etc. My findAll
methods signature has been changed to Either[CustomException, List[TEntity]]
, similarly findById
methods type is Either[CustomException, Option[TEntity]]
. 例如,我有一个中央存储库,它定义了
findAll
, findById
, insert
, delete
, update
, exists
等。我的findAll
方法签名已经改为Either[CustomException, List[TEntity]]
,类似的findById
方法类型是Either[CustomException, Option[TEntity]]
。
Now assume that, If I need to fetch employees from database in my method, i will be doing something like below : 现在假设,如果我需要在我的方法中从数据库中获取员工,我将执行以下操作:
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)
}
Now the type of vehicle will be Either[CustomException, Option[Vehicle]]
and type of driver is Either[CustomException, Employee]
现在车辆的类型将是
Either[CustomException, Option[Vehicle]]
和驱动程序的类型是Either[CustomException, Employee]
If i need to do any more operation after getting the results, i have to use case Right/Left and then do that. 如果我在获得结果后需要再做一些操作,我必须使用右/左案例然后再这样做。 The problem is that, may be inside the Right case, I might need to join with another table, which makes the result of that as again
Either[CustomException, Entity]
. 问题是,可能在Right的情况下,我可能需要与另一个表连接,这使得结果再次成为
Either[CustomException, Entity]
。 if any error occurs in that operation, i need to again use try catch block. 如果在该操作中发生任何错误,我需要再次使用try catch块。 I feel that this kind of hanling becomes very difficult to manage when the code complexity increases, and also I will have a lot of boiler plate code to handle these situations, which goes against Scala principle itself.
我觉得当代码复杂性增加时,这种处理变得非常难以管理,而且我将有很多锅炉板代码来处理这些情况,这违反了Scala原则本身。
So my question is, how can I handle exception in a better way without much boiler plate code. 所以我的问题是,如何在没有太多锅炉板代码的情况下以更好的方式处理异常。
Note : I am coming from a Java background, have been working on Scala only for a couple of months now. 注意:我来自Java背景,现在只在Scala工作了几个月。
EDIT 编辑
Adding Sample Code with Try : This sample is very close to the requirement I have. 使用Try添加示例代码:此示例非常接近我的要求。
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
But with the bove code, I am getting compilation errors. 但是使用bove代码,我收到了编译错误。
Error:(9, 6) type mismatch; found : scala.util.Try[(Int, String)] required: scala.collection.GenTraversableOnce[?] b <- checkTryStr ^ Error:(9, 6) type mismatch; found : scala.util.Try[(Int, String)] required: scala.collection.GenTraversableOnce[?] b <- checkTryStr ^ Error:(8, 6) type mismatch; found : List[Nothing] required: scala.util.Try[?] c <- a ^
You want to use the for
/ yield
sugar. 你想使用
for
/ yield
糖。 You can either get in the habit of putting .right
on all your Either
s, or as @Gangstead suggests, use \\/
from Scalaz. 您可以在推杆的习惯得到
.right
上所有Either
S,或@Gangstead表明,使用\\/
从Scalaz。 (There are certainly scary parts of Scalaz - I've been using it for 4 years and am still intimidated by eg Strength
- but it's perfectly possible to start with the easy parts and work your way up). (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 \/
Other vital hints: when you want to apply an effectful function to a List, you want to use Scalaz traverse
: 其他重要提示:当您想要将有效函数应用于List时,您希望使用Scalaz
traverse
:
vehicleList <- vehicleIdList.traverse(repository.findById) //assuming you're using \/
//might need a few .right if you're using Either
When you're calling Java code that might throw an exception, use scala.util.control.Exception
's catching
: 当你调用Java代码可能抛出一个异常,使用
scala.util.control.Exception
的catching
:
val myEither = catching(classOf[SomeException]) either someJavaMethodThatThrows()
// (...).disjunction if you're using \/.
If you need to work with another kind of "effectful context" at the same time as working with Either
/ \\/
, you'll have to start looking at monad transformers , but it might be best to get comfortable with just Either
first. 如果你需要在使用
Either
/ \\/
的同时使用另一种“有效的上下文”,你将不得不开始寻找monad变换器 ,但最好是先使用Either
。
Hope that helps; 希望有所帮助; best of luck, hope you like Scala.
祝你好运,希望你喜欢斯卡拉。
Take a look at Scalaz's disjunction \\/
. 看看Scalaz的分离
\\/
。
A warning: Scalaz is hardcore scala written by hardcore guys. 警告:Scalaz是由铁杆人写的硬核scala。
Take a look at Brendon McAdams' (@Rit) presentation about "Scalaz' Gateway Drugs" . 看看Brendon McAdams(@Rit)关于“Scalaz'Gateway Drugs”的演讲。 He's much more approachable for programmers coming from Java, and he keeps it very practicall
对于来自Java的程序员来说,他更加平易近人,而且他非常实用
You want to use Try
, not Either
. 你想使用
Try
,而不是Either
。 It is a monad, so you can map
or flatMap
it, or use it in a for
comprehension. 它是一个monad,所以你可以
map
或flatMap
它,或者用它for
理解。 It looks pretty elegant actually. 它实际上看起来很优雅。
def getVehicleWithDriver(id: String): Try [(Vehicle, Driver)] = for {
vehicle <- repository. findById(id)
driver <- empRepository.findById(vehicle.driverId)
} yield {
(vehicle, driver)
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.