복붙노트

[SCALA] 스칼라의 오버로드 생성자와 함께 자신의 예외를 정의

SCALA

스칼라의 오버로드 생성자와 함께 자신의 예외를 정의

자바에서 예외가 적어도 네 가지 생성자를 가지고 :

Exception() 
Exception(String message) 
Exception(String message, Throwable cause) 
Exception(Throwable cause) 

당신이 당신의 자신의 확장을 정의하려면, 당신은 단지 하위 예외를 선언하고 corresponden 슈퍼 생성자를 호출 원하는 각 생성자를 구현해야

당신은 어떻게 스칼라에서 같은 일을 달성 할 수 있습니까?

지금까지 지금은이 글이 SO의 대답을했다,하지만 난 그런 일반적인 일을 달성하는 쉬운 방법이있을 의심

해결법

  1. ==============================

    1.원인의 기본값은 null입니다. 그리고 메시지는 하나에 cause.toString ()는 null입니다 :

    원인의 기본값은 null입니다. 그리고 메시지는 하나에 cause.toString ()는 null입니다 :

    val e1 = new RuntimeException()
    
    e.getCause
    // res1: java.lang.Throwable = null
    
    e.getMessage
    //res2: java.lang.String = null
    
    val cause = new RuntimeException("cause msg")
    val e2 = new RuntimeException(cause)
    
    e.getMessage()
    //res3: String = java.lang.RuntimeException: cause msg
    

    그냥 기본값을 사용할 수 있도록 :

    class MyException(message: String = null, cause: Throwable = null) extends
      RuntimeException(MyException.defaultMessage(message, cause), cause)
    
    object MyException {
      def defaultMessage(message: String, cause: Throwable) =
        if (message != null) message
        else if (cause != null) cause.toString()
        else null
    }
    
    // usage:
    new MyException(cause = myCause)
    // res0: MyException = MyException: java.lang.RuntimeException: myCause msg
    
  2. ==============================

    2.물론, 이것은 내가 지금까지 발견했습니다 최고입니다

    물론, 이것은 내가 지금까지 발견했습니다 최고입니다

    class MissingConfigurationException private(ex: RuntimeException) extends RuntimeException(ex) {
      def this(message:String) = this(new RuntimeException(message))
      def this(message:String, throwable: Throwable) = this(new RuntimeException(message, throwable))
    }
    
    object MissingConfigurationException {
      def apply(message:String) = new MissingConfigurationException(message)
      def apply(message:String, throwable: Throwable) = new MissingConfigurationException(message, throwable)
    }
    

    이 방법 당신은 "새로운 MissingConfigurationException"를 사용할 수 있습니다 또는는 동반자 개체에서 방법을 적용

    어쨌든, 나는 아직 그것을 달성 할 수있는 간단한 방법이없는 것이 놀랍 네요

  3. ==============================

    3.당신은 Throwable.initCause를 사용할 수 있습니다.

    당신은 Throwable.initCause를 사용할 수 있습니다.

    class MyException (message: String, cause: Throwable) 
      extends RuntimeException(message) {
        if (cause != null)
          initCause(cause)
    
        def this(message: String) = this(message, null)  
    }
    
  4. ==============================

    4.나를 위해, 서로 동적 장력이 세 가지 요구가 나타납니다 :

    나를 위해, 서로 동적 장력이 세 가지 요구가 나타납니다 :

    하나는 3 번을 걱정하지 않는 경우,이 답변 (이 하나 피어는) 꽤 간결 보인다.

    하나 개의 값 숫자 3이 가능한 번호 1에 가까운 2 으려고 시도하는 동안 그러나,이 솔루션은 아래 효과적으로 스칼라 API로 자바 널 누출을 캡슐화합니다.

    class MyRuntimeException (
      val optionMessage: Option[String],
      val optionCause: Option[Throwable],
      val isEnableSuppression: Boolean,
      val isWritableStackTrace: Boolean
    ) extends RuntimeException(
      optionMessage match {
        case Some(string) => string
        case None => null
      },
      optionCause match {
        case Some(throwable) => throwable
        case None => null
      },
      isEnableSuppression,
      isWritableStackTrace
    ) {
      def this() =
        this(None, None, false, false)
      def this(message: String) =
        this(Some(message), None, false, false)
      def this(cause: Throwable) =
        this(None, Some(cause), false, false)
      def this(message: String, cause: Throwable) =
        this(Some(message), Some(cause), false, false)
    }
    

    당신이 MyRuntimeException 실제로 사용되는 경우 새로운를 사용하지 제거하고 싶은 경우에,이 동반자 개체를 추가 (이 단지 앞으로 모든 기존의 "마스터"클래스 생성자를 호출 적용의) :

    object MyRuntimeException {
      def apply: MyRuntimeException =
        MyRuntimeException()
      def apply(message: String): MyRuntimeException =
        MyRuntimeException(optionMessage = Some(message))
      def apply(cause: Throwable): MyRuntimeException =
        MyRuntimeException(optionCause = Some(cause))
      def apply(message: String, cause: Throwable): MyRuntimeException =
        MyRuntimeException(optionMessage = Some(message), optionCause = Some(cause))
      def apply(
        optionMessage: Option[String] = None,
        optionCause: Option[Throwable] = None,
        isEnableSuppression: Boolean = false,
        isWritableStackTrace: Boolean = false
      ): MyRuntimeException =
        new MyRuntimeException(
          optionMessage,
          optionCause,
          isEnableSuppression,
          isWritableStackTrace
        )
    }
    

    개인적으로, 나는 가능한 미래의 리팩토링을 용이하게하기 위해 가능한 한 너무 많은 코드로 새로운 운영자 실제로 억제를 사용하는 것을 선호합니다. 말했다 리팩토링은 공장 패턴에 강하게 발생하는 경우 특히 유용합니다. 내 최종 결과는, 더 자세한하면서, 클라이언트가 사용하기에 아주 좋은해야한다.

    object MyRuntimeException {
      def apply: MyRuntimeException =
        MyRuntimeException()
      def apply(message: String): MyRuntimeException =
        MyRuntimeException(optionMessage = Some(message))
      def apply(cause: Throwable): MyRuntimeException =
        MyRuntimeException(optionCause = Some(cause))
      def apply(message: String, cause: Throwable): MyRuntimeException =
        MyRuntimeException(optionMessage = Some(message), optionCause = Some(cause))
      def apply(
        optionMessage: Option[String] = None,
        optionCause: Option[Throwable] = None,
        isEnableSuppression: Boolean = false,
        isWritableStackTrace: Boolean = false
      ): MyRuntimeException =
        new MyRuntimeException(
          optionMessage,
          optionCause,
          isEnableSuppression,
          isWritableStackTrace
        )
    }
    
    class MyRuntimeException private[MyRuntimeException] (
      val optionMessage: Option[String],
      val optionCause: Option[Throwable],
      val isEnableSuppression: Boolean,
      val isWritableStackTrace: Boolean
    ) extends RuntimeException(
      optionMessage match {
        case Some(string) => string
        case None => null
      },
      optionCause match {
        case Some(throwable) => throwable
        case None => null
      },
      isEnableSuppression,
      isWritableStackTrace
    )
    

    보다 정교한 RuntimeException의 패턴을 탐색 :

    단지 원래의 질문에서 작은 도약 패키지 또는 API에 대한 전문들이 RuntimeException의 생태계를 만드는 욕망입니다. 아이디어는 특정 하위 예외의 새로운 생태계가 생성 할 수있는 "루트"의 RuntimeException을 정의하는 것입니다. 나를 위해, 캐치를 사용하고 오류의 특정 유형에 대한 악용 훨씬 쉽게 일치시키는 것이 중요했다.

    예를 들어, I는 케이스 클래스를 생성 할 수 있도록 이전 상태들의 세트를 정의 유효성 확인 방법을 가지고있다. 실패 각 조건은 RuntimeException의 인스턴스를 생성합니다. 그리고 RuntimeInstances의 목록이 방법으로 반환됩니다. 이것은 클라이언트에게 그들이 응답을 처리하려는 방법을 결정하는 기능을 제공합니다; 목록 잡고 예외를 던져 뭔가 특정의 목록을 스캔하거나 매우 비싼 JVM 던져 명령을 참여하지 않고 호출 체인까지 전체 일을 밀어 것을 던져.

    이 특정 문제 공간의 RuntimeException의 세 가지 다른 후손, 하나의 추상 (FailedPrecondition)와 두 개의 콘크리트 (FailedPreconditionMustBeNonEmptyList 및 FailedPreconditionsException)가 있습니다.

    첫 번째, FailedPrecondition는 RuntimeException을, MyRuntimeException 매우 유사에 직계 후손이며, (직접 인스턴스 생성을 방지하기 위해) 추상적이다. FailedPrecondition는 인스턴스 팩토리 (new 연산자를 억제)와 같은 역할을하는 "컴패니언 오브젝트 특성"FailedPreconditionObject있다.

    trait FailedPreconditionObject[F <: FailedPrecondition] {
      def apply: F =
        apply()
    
      def apply(message: String): F =
        apply(optionMessage = Some(message))
    
      def apply(cause: Throwable): F =
        apply(optionCause = Some(cause))
    
      def apply(message: String, cause: Throwable): F =
        apply(optionMessage = Some(message), optionCause = Some(cause))
    
      def apply(
          optionMessage: Option[String] = None
        , optionCause: Option[Throwable] = None
        , isEnableSuppression: Boolean = false
        , isWritableStackTrace: Boolean = false
      ): F
    }
    abstract class FailedPrecondition (
      val optionMessage: Option[String],
      val optionCause: Option[Throwable],
      val isEnableSuppression: Boolean,
      val isWritableStackTrace: Boolean
    ) extends RuntimeException(
      optionMessage match {
        case Some(string) => string
        case None => null
      },
      optionCause match {
        case Some(throwable) => throwable
        case None => null
      },
      isEnableSuppression,
      isWritableStackTrace
    )
    

    둘째, FailedPreconditionMustBeNonEmptyList 간접 RuntimeException의 자손과 FailedPrecondition 직접적인 구체적인 구현이다. 그것은 동반자 객체와 클래스를 모두 정의합니다. 컴패니언 객체는 특성 FailedPreconditionObject 확장합니다. 그리고 클래스는 단순히 최종 더 이상의 확장을 방지하기 위해 추상 클래스 FailedPrecondition 마크를 확장합니다.

    object FailedPreconditionMustBeNonEmptyList extends FailedPreconditionObject[FailedPreconditionMustBeNonEmptyList] {
      def apply(
          optionMessage: Option[String] = None
        , optionCause: Option[Throwable] = None
        , isEnableSuppression: Boolean = false
        , isWritableStackTrace: Boolean = false
      ): FailedPreconditionMustBeNonEmptyList =
        new FailedPreconditionMustBeNonEmptyList(
            optionMessage
          , optionCause
          , isEnableSuppression
          , isWritableStackTrace
        )
    }
    final class FailedPreconditionMustBeNonEmptyList private[FailedPreconditionMustBeNonEmptyList] (
        optionMessage: Option[String]
      , optionCause: Option[Throwable]
      , isEnableSuppression: Boolean
      , isWritableStackTrace: Boolean
    ) extends
      FailedPrecondition(
          optionMessage
        , optionCause
        , isEnableSuppression
        , isWritableStackTrace
      )
    

    셋째, FailedPrecondition 예외는 실패 전제 조건 목록을 래핑하고 동적 예외 메시지의 발광 관리 RuntimeException의 직접 하위이다.

    object FailedPreconditionsException {
      def apply(failedPrecondition: FailedPrecondition): FailedPreconditionsException =
        FailedPreconditionsException(List(failedPrecondition))
      def apply(failedPreconditions: List[FailedPrecondition]): FailedPreconditionsException =
        tryApply(failedPreconditions).get
      def tryApply(failedPrecondition: FailedPrecondition): Try[FailedPreconditionsException] =
        tryApply(List(failedPrecondition))
      def tryApply(failedPreconditions: List[FailedPrecondition]): Try[FailedPreconditionsException] =
        if (failedPreconditions.nonEmpty)
          Success(new FailedPreconditionsException(failedPreconditions))
        else
          Failure(FailedPreconditionMustBeNonEmptyList())
      private def composeMessage(failedPreconditions: List[FailedPrecondition]): String =
        if (failedPreconditions.size > 1)
          s"failed preconditions [${failedPreconditions.size}] have occurred - ${failedPreconditions.map(_.optionMessage.getOrElse("")).mkString("|")}"
        else
          s"failed precondition has occurred - ${failedPreconditions.head.optionMessage.getOrElse("")}"
    }
    final class FailedPreconditionsException private[FailedPreconditionsException] (
      val failedPreconditions: List[FailedPrecondition]
    ) extends RuntimeException(FailedPreconditionsException.composeMessage(failedPreconditions))
    

    그리고 전체적으로 깔끔한 것들로 그 함께 모두를 데리고, 나는 개체 FailedPreconditionsException 내에서 모두 FailedPrecondition 및 FailedPreconditionMustBeNonEmptyList 놓습니다. 그리고 이것은 최종 결과의 모습이 좋아하는 것입니다 :

    object FailedPreconditionsException {
      trait FailedPreconditionObject[F <: FailedPrecondition] {
        def apply: F =
          apply()
    
        def apply(message: String): F =
          apply(optionMessage = Some(message))
    
        def apply(cause: Throwable): F =
          apply(optionCause = Some(cause))
    
        def apply(message: String, cause: Throwable): F =
          apply(optionMessage = Some(message), optionCause = Some(cause))
    
        def apply(
            optionMessage: Option[String] = None
          , optionCause: Option[Throwable] = None
          , isEnableSuppression: Boolean = false
          , isWritableStackTrace: Boolean = false
        ): F
      }
      abstract class FailedPrecondition (
          val optionMessage: Option[String]
        , val optionCause: Option[Throwable]
        , val isEnableSuppression: Boolean
        , val isWritableStackTrace: Boolean
      ) extends RuntimeException(
        optionMessage match {
          case Some(string) => string
          case None => null
        },
        optionCause match {
          case Some(throwable) => throwable
          case None => null
        },
        isEnableSuppression,
        isWritableStackTrace
      )
    
      object FailedPreconditionMustBeNonEmptyList extends FailedPreconditionObject[FailedPreconditionMustBeNonEmptyList] {
        def apply(
            optionMessage: Option[String] = None
          , optionCause: Option[Throwable] = None
          , isEnableSuppression: Boolean = false
          , isWritableStackTrace: Boolean = false
        ): FailedPreconditionMustBeNonEmptyList =
          new FailedPreconditionMustBeNonEmptyList(
              optionMessage
            , optionCause
            , isEnableSuppression
            , isWritableStackTrace
          )
      }
      final class FailedPreconditionMustBeNonEmptyList private[FailedPreconditionMustBeNonEmptyList] (
          optionMessage: Option[String]
        , optionCause: Option[Throwable]
        , isEnableSuppression: Boolean
        , isWritableStackTrace: Boolean
      ) extends
        FailedPrecondition(
            optionMessage
          , optionCause
          , isEnableSuppression
          , isWritableStackTrace
        )
    
      def apply(failedPrecondition: FailedPrecondition): FailedPreconditionsException =
        FailedPreconditionsException(List(failedPrecondition))
    
      def apply(failedPreconditions: List[FailedPrecondition]): FailedPreconditionsException =
        tryApply(failedPreconditions).get
    
      def tryApply(failedPrecondition: FailedPrecondition): Try[FailedPreconditionsException] =
        tryApply(List(failedPrecondition))
    
      def tryApply(failedPreconditions: List[FailedPrecondition]): Try[FailedPreconditionsException] =
        if (failedPreconditions.nonEmpty)
          Success(new FailedPreconditionsException(failedPreconditions))
        else
          Failure(FailedPreconditionMustBeNonEmptyList())
      private def composeMessage(failedPreconditions: List[FailedPrecondition]): String =
        if (failedPreconditions.size > 1)
          s"failed preconditions [${failedPreconditions.size}] have occurred - ${failedPreconditions.map(_.optionMessage.getOrElse("")).mkString("|")}"
        else
          s"failed precondition has occurred - ${failedPreconditions.head.optionMessage.getOrElse("")}"
    }
    final class FailedPreconditionsException private[FailedPreconditionsException] (
      val failedPreconditions: List[FailedPreconditionsException.FailedPrecondition]
    ) extends RuntimeException(FailedPreconditionsException.composeMessage(failedPreconditions))
    

    그리고 이것은 클라이언트가 자신의 예외 유도라는 FailedPreconditionMustBeNonEmptyString을 만들 수 위의 코드를 사용하기 같을 것이다 것입니다 :

    object FailedPreconditionMustBeNonEmptyString extends FailedPreconditionObject[FailedPreconditionMustBeNonEmptyString] {
      def apply(
          optionMessage: Option[String] = None
        , optionCause: Option[Throwable] = None
        , isEnableSuppression: Boolean = false
        , isWritableStackTrace: Boolean = false
      ): FailedPreconditionMustBeNonEmptyString =
        new FailedPreconditionMustBeNonEmptyString(
            optionMessage
          , optionCause
          , isEnableSuppression
          , isWritableStackTrace
        )
    }
    final class FailedPreconditionMustBeNonEmptyString private[FailedPreconditionMustBeNonEmptyString] (
        optionMessage: Option[String]
      , optionCause: Option[Throwable]
      , isEnableSuppression: Boolean
      , isWritableStackTrace: Boolean
    ) extends
      FailedPrecondition(
          optionMessage
        , optionCause
        , isEnableSuppression
        , isWritableStackTrace
      )
    

    그리고이 예외의 사용은 다음과 같습니다 :

    throw FailedPreconditionMustBeNonEmptyString()
    

    나는 그렇게 어려운 특정에서의 RuntimeException을-ifying 스칼라 또는 내가 자바 때 너무 편안 성장있는 더 일반적인 "예외 생태계 '로 확장하는 구체적이고 포괄적 인 모두있는 아무것도 가까이 위치를 찾을 때문에 원래의 질문에 대답 잘 넘어 갔다 .

    내가 의견을 듣고 싶네요 내 솔루션 세트에 (에 변화가 아닌 "와우 너무 자세한 나를 위해의 방법입니다. 그"). 그리고 추가 최적화 또는 나는이 패턴의 클라이언트에 대해 생성 한 값이나 간결성의 손실없이 상세를 줄일 수있는 방법을 사랑합니다.

  5. ==============================

    5.시도 / catch 블록에서 스칼라 패턴 매칭은 인터페이스에서 작동합니다. 내 솔루션은 예외 이름에 대한 인터페이스를 사용하여 별도의 클래스 인스턴스를 사용하는 것입니다.

    시도 / catch 블록에서 스칼라 패턴 매칭은 인터페이스에서 작동합니다. 내 솔루션은 예외 이름에 대한 인터페이스를 사용하여 별도의 클래스 인스턴스를 사용하는 것입니다.

    trait MyException extends RuntimeException
    
    class MyExceptionEmpty() extends RuntimeException with MyException
    
    class MyExceptionStr(msg: String) extends RuntimeException(msg) with MyException
    
    class MyExceptionEx(t: Throwable) extends RuntimeException(t) with MyException
    
    object MyException {
      def apply(): MyException = new MyExceptionEmpty()
      def apply(msg: String): MyException = new MyExceptionStr(msg)
      def apply(t: Throwable): MyException = new MyExceptionEx(t)
    }
    
    class MyClass {
      try {
        throw MyException("oops")
      } catch {
        case e: MyException => println(e.getMessage)
        case _: Throwable => println("nope")
      }
    }
    

    인스턴스화 MyClass에 출력합니다 "죄송합니다".

  6. ==============================

    6.여기 로마 - 보리 소프하지만 더 형태 보증 @의 것과 유사한 방식이다.

    여기 로마 - 보리 소프하지만 더 형태 보증 @의 것과 유사한 방식이다.

    case class ShortException(message: String = "", cause: Option[Throwable] = None)
        extends Exception(message) {
      cause.foreach(initCause)
    }
    

    그런 다음 자바 방식으로 예외를 만들 수 있습니다 :

    throw ShortException() 
    throw ShortException(message) 
    throw ShortException(message, Some(cause)) 
    throw ShortException(cause = Some(cause)) 
    
  7. from https://stackoverflow.com/questions/10925268/define-your-own-exceptions-with-overloaded-constructors-in-scala by cc-by-sa and MIT license