如何在Scala中创建自定义异常,扩展Exception
类,并在发生异常时抛出它们并捕获它们。
java中的例子:
class CustomException extends Exception {
public final static String _FAIL_TO_INSERT = "FAIL_TO_INSERT";
}
答案 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
不会被覆盖。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))
}
答案 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 class
个Exception
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 并在应用程序/控制器边界上对其进行解构(模式匹配)。