scala中的自定义异常

时间:2016-07-07 10:48:18

标签: scala exception

如何在Scala中创建自定义异常,扩展Exception类,并在发生异常时抛出它们并捕获它们。

java中的例子:

class CustomException extends Exception {

  public final static String _FAIL_TO_INSERT = "FAIL_TO_INSERT";

}

7 个答案:

答案 0 :(得分:40)

final case class CustomException(private val message: String = "", 
                           private val cause: Throwable = None.orNull)
                      extends Exception(message, cause) 

试试看:

try {
    throw CustomException("optional")
} catch {
    case c: CustomException =>
          c.printStackTrace
}

答案 1 :(得分:17)

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)
  }
}

这几乎与@Jacek L.的答案完全相同。我只是想对这个答案背后的动机添加一些更多的信息。

为什么这么多的构造函数?

Throwable是以一种有趣的方式写的。它有4个构造函数 - 忽略具有boolean切换的那个 - 它们中的每一个与null的行为略有不同,并且这些差异只能由多个构造函数维护。

如果Scala允许通过super调用超类构造函数,那会更加清晰,但它不会:(

为什么不是案例类?

  • 完美地维护构造者'关于null的行为是不可能的;具体而言,def this()def this(message: String)都必须将cause设置为null,而最初设置为this
  • toString不会被覆盖。
  • 邮件和原因已通过getMessagegetCause公开发布。添加另一个引用是多余的。
  • 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))
}

答案 2 :(得分:6)

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

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
}

然后你可以拥有尽可能多case classException es,不仅可以扩展case class CustomeException(message: String) extends Exception(message) with MyException { override val details: JsValue = Json.obj( "message" -> message, "etc" -> "Anything else") } ,还可以扩展你的新特性。

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)
    }

现在,使用Scala的全部目标是向更具功能性的编程风格迈进,它将使您的应用程序更加并发,因此如果您需要使用新的自定义异常,您可能想尝试这样的事情:

void setEntry( final String alias, String aValue ){
    SecretKey secretKey = null;
    try{
        secretKey = KeyGenerator.getInstance("AES", PROVIDER.getName()).generateKey();
    }
    catch ( NoSuchAlgorithmException |NoSuchProviderException aE ){ aE.printStackTrace(); }

// store the secret key
    KeyStore.Entry keyStoreEntry = new KeyStore.SecretKeyEntry( secretKey );
    ProtectionParameter keyPassword = new PasswordProtection( aValue.toCharArray() );

    try{
        mKEYSTORE.setEntry( alias, keyStoreEntry, keyPassword );
    }catch ( KeyStoreException X ){
        X.printStackTrace();
        mLog.debug( X.getMessage() ); }

}//setEntry()


String getEntry( entryType aEntryType ){
    String retVal;
    try{
        KeyStore.SecretKeyEntry secretKeyEntry = (SecretKeyEntry) mKEYSTORE.getEntry( aEntryType.name(), null );
        retVal = new String( secretKeyEntry.getSecretKey().getEncoded() );
    }catch ( NoSuchAlgorithmException | UnrecoverableEntryException | KeyStoreException X ){
        mLog.error( X.getMessage() );
        retVal = "ERROR getEntry";
    }
    return retVal;
}//getEntry()


void genKeyStore(){
    try{
        mKEYSTORE = KeyStore.getInstance( "BKS", "SC" );
//Pass null as the stream argument to initialize an empty KeyStore or to initialize a KeyStore which does not rely on an InputStream.
        mKEYSTORE.load( null, "KSpw".toCharArray(); );
        mLog.debug( "mKEYSTORE init'd" );
    }
    catch ( KeyStoreException | NoSuchProviderException | IOException | NoSuchAlgorithmException | CertificateException X )
    {throw X;}
}//genKeyStore()

答案 3 :(得分:6)

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

这也可以通过前面答案中提到的特征来实现。在这种情况下,我不会创建单独的类:

trait SomeException { self: Throwable =>
  def someDetail: SomeDetail
}

然后,投掷时:

throw new Exception(...) with SomeException {
  override val someDetail = ...
}

和匹配时:

try {
  ...
} catch {
  case ex: Throwable with SomeException =>
    ex.getCause
    ex.getMessage
    ex.someDetail
}

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

或多或少那样的东西。

答案 4 :(得分:3)

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

case class CustomException(s: String)  extends Exception(s)

你可以抛出这样的异常:

try{
...
} catch{
case x:Exception => throw new CustomException("whatever")
}

答案 5 :(得分:1)

与其他答案类似,但我更喜欢使用同伴对象而不是替代构造函数。

class MyException(message: String, cause: Throwable = null) extends Exception(message, cause)

object MyException {
  def apply(message: String): MyException = new MyException(message)
  def apply(message: String, cause: Throwable): MyException = new MyException(message, cause)
}

答案 6 :(得分:0)

添加到上面的所有答案中,如果您根本想拥有一个错误层次结构,则抽象类会有所帮助。

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")

使用trait代替抽象类也是可能的,但是它们受到限制,因为它们没有构造函数参数。

可能在任何地方使用 GenericError 并在应用程序/控制器边界上对其进行解构(模式匹配)。