scala中的自定义异常

Nil*_*esh 35 scala exception

我如何在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)

  • 我实际上会避免使用案例类.`toString`已经实现,而`equals`将被覆盖并且行为与其他异常不同(`Exception`使用默认的`Object.equals`).此外,通过`getMessage`和`getCause`已经可以公开访问消息和原因.如果需要模式匹配,请实现`unapply`方法. (2认同)

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)将要设置causenull,而最初它被设置为this.
  • toString 不会被覆盖.
  • 消息和原因已经通过getMessage和公开发布getCause.添加另一个参考是多余的.
  • equals将被覆盖,并将表现不同.
    意思是,new Exception("m") == new Exception("m") // false
    new 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)

  • @NickGinanto在`MyException`类中有两个带有单个参数的构造函数 - 主要的一个带有`message:String`,另一个带有`cause:Throwable`.编译器无法将调用推断为"this(null)",因为它适用于这两个构造函数.指定`null`的类型告诉编译器要调用哪个构造函数. (2认同)

Mes*_*dón 7

您可能想要创建一个密封的特征:

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,而是需要使用特征的人来扩展它.这样做的好处是,因为scala要求您使用特定的构造函数进行扩展,所以使用此解决方案,您不会只与异常中的许多构造函数中的一个结合. (2认同)

Jac*_* L. 7

为了反映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)

这里的优点是您不会坚持父异常的任何特定构造函数.

或多或少那样的东西.


hmi*_*nle 6

您可以像这样定义自定义异常

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)