scala Scala中的自定义异常
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/38243530/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Custom Exception in scala
提问by Nilesh
how can i create custom exceptions in Scala extending Exceptionclass and throw them when exception occurs as well as catch them.
我如何在 Scala 扩展Exception类中创建自定义异常并在异常发生时抛出它们以及捕获它们。
example in java :
java中的例子:
class CustomException extends Exception {
public final static String _FAIL_TO_INSERT = "FAIL_TO_INSERT";
}
回答by Andrzej Jozwik
final case class CustomException(private val message: String = "",
private val cause: Throwable = None.orNull)
extends Exception(message, cause)
Just try catch:
试试捕捉:
try {
throw CustomException("optional")
} catch {
case c: CustomException =>
c.printStackTrace
}
回答by Eyal Roth
class MyException(message: String) extends Exception(message) {
def this(message: String, cause: Throwable) {
this(message)
initCause(cause)
}
def this(cause: Throwable) {
this(Option(cause).map(_.toString).orNull, cause)
}
def this() {
this(null: String)
}
}
This is almost identical to @Jacek L.'s answer. I just wanted to add some more input on the motive behind this answer.
这与@Jacek L. 的回答几乎相同。我只是想对这个答案背后的动机添加更多的输入。
Why so many constructors?
为什么有这么多构造函数?
Throwableis written in kind of a funny way. It has 4 constructors
-- ignoring the one with the booleantoggles -- each of them behaves a bit differently with nulls, and these differences could only be maintained with multiple constructors.
Throwable以一种有趣的方式写成。它有 4 个构造函数——忽略带有boolean切换的那个——它们中的每一个与nulls 的行为有点不同,并且这些差异只能通过多个构造函数来维护。
It would have been a bit cleaner if Scala would have allowed to call a superclass constructor via super, but it doesn't :(
如果 Scala 允许通过 调用超类构造函数super,它会更清晰一些,但它没有:(
Why not a case class?
为什么不是案例类?
- Perfectly maintaining the constructors' behavior regarding
nulls wouldn't be possible; specifically, bothdef this()anddef this(message: String)will have to set thecausetonull, while originally it is set tothis. toStringwill not be overridden.- The message and the cause are already publicly available via
getMessageandgetCause. Adding another reference to these is redundant. equalswill be overridden and will behave differently.
Meaning,new Exception("m") == new Exception("m") // false
whilenew CaseException("m") == new CaseException("m") // true
- 完美地维护构造函数关于
nulls的行为是不可能的;具体来说,def this()和def this(message: String)都必须将 设置cause为null,而最初设置为this。 toString不会被覆盖。- 该消息和原因已通过
getMessage和公开提供getCause。添加对这些的另一个引用是多余的。 equals将被覆盖并且行为会有所不同。
意思是,new Exception("m") == new Exception("m") // false
同时new CaseException("m") == new CaseException("m") // true
If one desires to access the message and the cause via pattern-matching, one can simply implement the unapplymethod:
如果希望通过模式匹配访问消息和原因,可以简单地实现该unapply方法:
object MyException {
def unapply(e: MyException): Option[(String,Throwable)] = Some((e.getMessage, e.getCause))
}
回答by Mesi Rendón
You might want to create a sealed trait:
您可能想要创建一个密封的特征:
sealed trait MyException {
self: Throwable => //This is called self annotations and you can use "self" or "dog" or whatever you want, it requires that those who extend this trait must also extend a Throwable or a subclass of it.
val message: String
val details: JsValue
}
Then you can have as many case classes as you need extending not only Exceptionbut your new trait.
然后你可以拥有尽可能多的case classes,不仅需要扩展,还可以扩展Exception你的新特性。
case class CustomeException(message: String) extends Exception(message) with MyException {
override val details: JsValue = Json.obj( "message" -> message, "etc" -> "Anything else")
}
Now, the whole point of using Scala is walking towards a more functional programming style, it will make your app more concurrent, so if you need to use your new custom exception, you might want to try something like this:
现在,使用 Scala 的重点是走向更函数式的编程风格,它会让你的应用程序更具并发性,所以如果你需要使用新的自定义异常,你可能想尝试这样的事情:
def myExampleMethod(s: Option[String]): Future[Boolean] = {
Try(
s match {
case Some(text) =>
text.lenght compareTo 5 match {
case 1 => true
case _ => false
}
case _ => throw CustomeException("Was expecting some txt")
}
)
match {
case Success(bool) => Future.success(bool)
case Failure(e) => Future.failed(e)
}
回答by Jacek L.
In order to reflect all the original constructors from Exception I'd implement a custom exception with the following pattern:
为了反映 Exception 的所有原始构造函数,我将使用以下模式实现自定义异常:
class CustomException(msg: String) extends Exception(msg) {
def this(msg: String, cause: Throwable) = {
this(msg)
initCause(cause)
}
def this(cause: Throwable) = {
this(Option(cause).map(_.toString).orNull)
initCause(cause)
}
def this() = {
this(null: String)
}
}
This can be also achieved with a trait as mentioned in previous answer. I'd just not create individual classes in this case:
这也可以通过前面的答案中提到的特征来实现。在这种情况下,我不会创建单独的类:
trait SomeException { self: Throwable =>
def someDetail: SomeDetail
}
then, when throwing:
然后,当投掷时:
throw new Exception(...) with SomeException {
override val someDetail = ...
}
and when matching:
匹配时:
try {
...
} catch {
case ex: Throwable with SomeException =>
ex.getCause
ex.getMessage
ex.someDetail
}
The advantage here is that you are not sticking to any particular constructor of the parent exception.
这里的优点是您不会坚持使用父异常的任何特定构造函数。
something more or less like that.
或多或少是这样的。
回答by hminle
You define your custom exception like this
您像这样定义自定义异常
case class CustomException(s: String) extends Exception(s)
And you can throw your exception like this:
你可以像这样抛出你的异常:
try{
...
} catch{
case x:Exception => throw new CustomException("whatever")
}
回答by Gagandeep Kalra
Adding to all the answers above, If at all you want to have an error hierarchy, abstract classwould help.
添加到上面的所有答案中,如果您想要一个错误层次结构,抽象类会有所帮助。
abstract class GenericError(message: String) extends Exception(message)
case class SpecificErrorA(message: String) extends GenericError(message)
case class SpecificErrorB(message: String) extends GenericError(message)
throw new SpecificErrorA("error on A") OR throw new SpecificErrorB("error on B")
The same is possible using trait instead of an abstract class but they are limited in that they do not have constructor parameters.
使用 trait 而不是抽象类也是可能的,但它们的局限性在于它们没有构造函数参数。
Probably use GenericErroreverywhere and deconstruct (pattern match) it on the application/controller boundary.
可能到处使用GenericError并在应用程序/控制器边界上解构(模式匹配)它。

