Пользовательское исключение в scala
Как я могу создавать пользовательские исключения в Scala, расширяющий класс Exception
и генерировать их при возникновении исключений, а также перехватывать их.
пример в Java:
class CustomException extends Exception {
public final static String _FAIL_TO_INSERT = "FAIL_TO_INSERT";
}
Ответы
Ответ 1
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
}
Ответ 2
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
s, и эти различия могут поддерживаться только с несколькими конструкторами.
Было бы немного чище, если Scala разрешил бы вызвать конструктор суперкласса через super
, но это не так: (
Почему не класс case?
- Прекрасно поддерживать поведение конструкторов в отношении
null
было бы невозможно; в частности, как 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
Если кто-то желает получить доступ к сообщению и причине с помощью сопоставления с образцом, можно просто реализовать метод unapply
:
object MyException {
def unapply(e: MyException): Option[(String,Throwable)] = Some((e.getMessage, e.getCause))
}
Ответ 3
Возможно, вы захотите создать запечатанную черту:
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 class
сколько вам нужно, чтобы расширить не только Exception
но и вашу новую черту.
case class CustomeException(message: String) extends Exception(message) with MyException {
override val details: JsValue = Json.obj( "message" -> message, "etc" -> "Anything else")
}
Теперь весь смысл использования 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)
}
Ответ 4
Чтобы отразить все исходные конструкторы из 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
}
Преимущество в том, что вы не придерживаетесь какого-либо конкретного конструктора родительского исключения.
нечто более или менее подобное.
Ответ 5
Вы определяете свое настраиваемое исключение, подобное этому
case class CustomException(s: String) extends Exception(s)
И вы можете сделать свое исключение следующим образом:
try{
...
} catch{
case x:Exception => throw new CustomException("whatever")
}
Ответ 6
Добавление ко всем ответам выше, если вы вообще хотите иметь иерархию ошибок, поможет абстрактный класс.
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 везде и деконструируйте (сопоставление с образцом) его на границе приложения/контроллера.