63 votes

Exception personnalisée dans scala

comment puis-je créer des exceptions personnalisées dans Scala en étendant la classe Exception et les lancer quand une exception se produit ainsi que les attraper.

exemple en java:

 class CustomException extends Exception {

  public final static String _FAIL_TO_INSERT = "FAIL_TO_INSERT";

}
 

73voto

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

Essayez juste d'attraper:

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

41voto

errr Points 444
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)
  }
}

C'est presque identique à @Jacek L. de réponse. Je voulais juste ajouter un peu plus d'entrée sur le motif derrière cette réponse.

Pourquoi de nombreux constructeurs?

Throwable est écrit dans une sorte de drôle de façon. Il dispose de 4 constructeurs -- en ignorant l'un avec l' boolean bascule -- chacun d'eux se comporte un peu différemment avec nulls, et ces différences ne peuvent être maintenus avec plusieurs constructeurs.

Il aurait été un peu plus propre si Scala aurait permis d'appeler un constructeur de la superclasse via super, mais il n'a pas :(

Pourquoi pas une affaire de classe?

  • Parfaitement maintenir les constructeurs de comportement concernant l' nulls ne serait pas possible; en particulier, les deux def this() et def this(message: String) devrez définir le cause de null, alors qu'au départ, il est mis à l' this.
  • toString ne sera pas remplacée.
  • Le message et la cause sont déjà accessibles au public via getMessage et getCause. L'ajout d'une autre référence à ces est redondante.
  • equals sera remplacée et va se comporter différemment.
    Signification, new Exception("m") == new Exception("m") // false
    alors qu' new CaseException("m") == new CaseException("m") // true

Si l'on désire accéder au message et à la cause via le pattern matching, on peut simplement mettre en œuvre l' unapply méthode:

object MyException {
  def unapply(e: MyException): Option[(String,Throwable)] = Some((e.getMessage, e.getCause))
}

11voto

Mesi Rendón Points 151

Vous voudrez peut-être créer un trait scellé:

 sealed trait MyException {
    self: Throwable => //This is called self annotations and you can use "self" or "dog" or whatever you want, it requires from those who extend this trait, to also extend a Throwable or a subclass of it.
    val: message: String
    val: details: JsValue
}
 

Ensuite, vous pouvez avoir autant de case class es que vous avez besoin d'étendre non seulement Exception mais aussi votre nouveau trait.

 case class CustomeException(message: String) extends Exception(message) with MyException {
    override val details: JsValue = Json.obj( "message" -> message, "etc" -> "Anything else")
}
 

Maintenant, l'intérêt d'utiliser Scala va vers un style de programmation plus fonctionnel, cela rendra votre application plus concurrente, donc si vous avez besoin d'utiliser votre nouvelle exception personnalisée, vous voudrez peut-être essayer quelque chose comme ceci:

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

9voto

Jacek L. Points 511

Afin de tenir compte de tous les premiers constructeurs d'Exception que j'avais de mettre en œuvre une exception personnalisée avec le motif suivant:

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

Cela peut aussi être réalisée avec un trait comme mentionné dans la réponse précédente. Je venais juste de ne pas créer des classes dans ce cas:

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

ensuite, en lançant:

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

et lors de la correspondance:

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

L'avantage ici est que vous n'êtes pas coller à un constructeur de la mère exception.

quelque chose de plus ou moins comme ça.

6voto

hminle Points 146

Vous définissez votre exception personnalisée comme ceci

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

Et vous pouvez lever votre exception comme ceci:

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X