2016-07-07 63 views
19

如何在Scala中創建自定義異常並將其延伸到Exception類中,並在發生異常時將其拋出並捕獲它們。scala中的自定義異常

例如在Java中:

class CustomeException extends Exception { 

    public final static String _FAIL_TO_INSERT = "FAIL_TO_INSERT"; 

} 

回答

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

剛剛嘗試捕獲:

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

對不起,我沒有意思是降低這一點,我只是想刪除upvote。 – caeus

+0

我實際上避免使用案例類。 'toString'已經實現,而'equals'將被覆蓋,並且行爲與其他異常不同('Exception'使用默認的'Object.equals')。此外,公共訪問消息和原因已經可以通過'getMessage'和'getCause'獲得。如果你想要模式匹配,實現'unapply'方法。 –

+0

異常並非設計爲映射中的關鍵,您爲什麼要比較異常?方法toString返回與Exception相同的結果(你測試了嗎?)。我將改變消息的可見性並導致私密以隱藏細節。 –

-1

你這樣定義

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

您的自定義異常,你可以把你的例外,像這個:

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

您可能希望創建一個密封的特點:

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 
} 

然後你可以有很多case class ES,因爲你需要延長不僅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) 
    } 
+2

它不必被密封,但是如果您需要模式匹配例外,它可以幫助編譯器。我喜歡這個答案,因爲這個特質本身沒有擴展這個例外,但需要那些使用特質的人來擴展它。這樣做的好處是,因爲scala需要使用特定的構造函數進行擴展,所以對於這種解決方案,您並不僅僅是一個異常所具有的構造函數之一。 – caeus

+0

我認爲在'val:'中有一個不必要的':'有一個錯字。我無法編輯問題,因爲顯然_建議的編輯隊列已滿。 – botchniaque

3

爲了反映所有從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 
} 

這裏的好處是,你是不是堅持父異常的任何特定構造函數。

或多或少的東西。

+0

感謝Jacek的幫助。 – Nilesh

9
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的行爲有點不同,並且這些差異只能由多個構造函數維護。

它會被清潔了一下,如果斯卡拉將允許通過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)) 
}