我如何在Scala扩展Exception类中创建自定义异常,并在发生异常时抛出它们并捕获它们.
java中的示例:
class CustomException extends Exception {
public final static String _FAIL_TO_INSERT = "FAIL_TO_INSERT";
}
Run Code Online (Sandbox Code Playgroud)
And*_*wik 43
final case class CustomException(private val message: String = "",
private val cause: Throwable = None.orNull)
extends Exception(message, cause)
Run Code Online (Sandbox Code Playgroud)
试试看:
try {
throw CustomException("optional")
} catch {
case c: CustomException =>
c.printStackTrace
}
Run Code Online (Sandbox Code Playgroud)
Eya*_*oth 20
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)
}
}
Run Code Online (Sandbox Code Playgroud)
这几乎与@Jacek L.的答案完全相同.我只想在这个答案背后的动机上添加一些更多的信息.
为什么这么多建设者呢?
Throwable是以一种有趣的方式写的.它有4个构造函数 - 忽略带有boolean切换的构造函数 - 每个构造函数与nulls的行为略有不同,这些差异只能由多个构造函数维护.
如果Scala允许通过调用超类构造函数super,它本来会更清洁,但它不会:(
为什么不是案例类?
nulls 的行为是不可能的; 具体而言,既def this()和def this(message: String)将要设置cause到null,而最初它被设置为this.toString 不会被覆盖.getMessage和公开发布getCause.添加另一个参考是多余的.equals将被覆盖,并将表现不同.new Exception("m") == new Exception("m") // falsenew CaseException("m") == new CaseException("m") // true如果想要通过模式匹配来访问消息和原因,可以简单地实现该unapply方法:
object MyException {
def unapply(e: MyException): Option[(String,Throwable)] = Some((e.getMessage, e.getCause))
}
Run Code Online (Sandbox Code Playgroud)
您可能想要创建一个密封的特征:
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
}
Run Code Online (Sandbox Code Playgroud)
然后你可以拥有尽可能多的case classes,不仅可以扩展Exception你的新特性.
case class CustomeException(message: String) extends Exception(message) with MyException {
override val details: JsValue = Json.obj( "message" -> message, "etc" -> "Anything else")
}
Run Code Online (Sandbox Code Playgroud)
现在,使用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)
}
Run Code Online (Sandbox Code Playgroud)
为了反映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)
}
}
Run Code Online (Sandbox Code Playgroud)
这也可以通过前面答案中提到的特征来实现.在这种情况下,我不会创建单独的类:
trait SomeException { self: Throwable =>
def someDetail: SomeDetail
}
Run Code Online (Sandbox Code Playgroud)
扔的时候:
throw new Exception(...) with SomeException {
override val someDetail = ...
}
Run Code Online (Sandbox Code Playgroud)
并在匹配时:
try {
...
} catch {
case ex: Throwable with SomeException =>
ex.getCause
ex.getMessage
ex.someDetail
}
Run Code Online (Sandbox Code Playgroud)
这里的优点是您不会坚持父异常的任何特定构造函数.
或多或少那样的东西.
您可以像这样定义自定义异常
case class CustomException(s: String) extends Exception(s)
Run Code Online (Sandbox Code Playgroud)
你可以像这样抛出异常:
try{
...
} catch{
case x:Exception => throw new CustomException("whatever")
}
Run Code Online (Sandbox Code Playgroud)