にオーバーロードされたコンストラクタを使用して独自の例外を定義し、少なくともこれら四つのコンストラクタを持っています対応するスーパーコンストラクタを呼び出すコンストラクタJava例外ではScalaの
どのようにスカラで同じことを達成できますか?
は、これまでのところ、今、私はthis articleと、このSO answerを見ましたが、私は
にオーバーロードされたコンストラクタを使用して独自の例外を定義し、少なくともこれら四つのコンストラクタを持っています対応するスーパーコンストラクタを呼び出すコンストラクタJava例外ではScalaの
どのようにスカラで同じことを達成できますか?
は、これまでのところ、今、私はthis articleと、このSO answerを見ましたが、私は
cause
のデフォルト値はnullです。そしてmessage
ことが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
だけでなく、このような共通点を達成するための簡単な方法がなければならない疑いがある、これは私が見つけた最高です、これまで
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」を使用するか、とにかくコンパニオンオブジェクト
から方法を適用することができるこの方法は、私はまだそれ
を達成するための簡単な方法がないことを驚いていますあなたはThrowable.initCause
を使用することができます。私に
class MyException (message: String, cause: Throwable)
extends RuntimeException(message) {
if (cause != null)
initCause(cause)
def this(message: String) = this(message, null)
}
は、相互に動的なテンションを持っている三つの異なるニーズがあります表示されます。
RuntimeException
のエクステンダーの利便性。すなわち、子孫を作成するために書かれるべき最小限のコードRuntimeException
に恐ろしいのJava null
漏れ回避する
ただし、1と2にできるだけ近づけようとすると数値が3になる場合、以下のソリューションはJava null
をScala 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
が実際に使用されnew
を使用する必要が排除したい場合は、このコンパニオンオブジェクトを追加します(これは単に転送既存の「マスター」クラスのコンストラクタへの適用のコールのすべて):
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
)
}
個人的には、可能な限り多くのコードでnew
演算子の使用を実際に抑制し、将来のリファクタリングを容易にすることを好みます。リファクタリングがFactoryパターンに強く起こった場合は、特に役立ちます。私の最終的な結果は、より冗長ではあるが、クライアントが使用するのにはすばらしいものでなければならない。より洗練されたのRuntimeExceptionパターン探る
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
)
:
をそれは、パッケージやAPIに特化RuntimeException
秒の生態系を作成することを望むために元の質問からわずかな飛躍です。このアイデアは、特定の子孫例外の新しいエコシステムを作成できる「ルート」RuntimeException
を定義することです。私にとっては、catch
とmatch
を使って特定の種類のエラーを悪用するほうがはるかに簡単です。
例えば、ケースクラスの作成を許可する前に一連の条件を検証するvalidate
メソッドが定義されています。失敗した各条件は、RuntimeException
インスタンスを生成します。そして、RuntimeInstance
のListがメソッドによって返されます。これにより、クライアントは応答をどのように処理するかを決めることができます。 throw
リスト保留例外では、特定のものをリストでスキャンしてthrow
をスキャンするか、非常に高価なJVM throw
コマンドを使用せずに、コールチェーン全体をプッシュするだけです。
この特定の問題空間はRuntimeException
、1つの抽象(FailedPrecondition
)及び(FailedPreconditionMustBeNonEmptyList
とFailedPreconditionsException
)2コンクリートの三つの異なる子孫を持っています。
まず、FailedPrecondition
は、MyRuntimeException
に非常に類似しRuntimeException
への直接の子孫であり、および(直接インスタンス化を防止する)抽象的です。 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
を拡張し、それ以上の拡張を防ぐためにfinal
とマークします。
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
)
第三、FailedPreconditionsException
、例外メッセージの発光を管理する動的次いでList
FailedPrecondition
のSをラップし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
の両方を配置します。そして、これは、最終的な結果は次のようになります。FailedPreconditionMustBeNonEmptyString
と呼ば
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))
そして、これは、それが自分の例外導出を作成するために、上記のコードを使用するようにクライアントのためにどのように見えるかです:
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()
私はそれはとても難しいanythを見つけたので、私は元の質問に答えるを超えてうまくいった具体的にはRuntimeException
でScala-ifyingで具体的かつ包括的であることに近づくか、より一般的な「例外エコシステム」に至るまで、Javaで快適になった。
私の解決策のセットでは、フィードバックをお聞きしたいと思います(「Wow!これは私にとってはあまりにも冗長です」)。そして私は、このパターンのクライアントのために生成した値や簡潔さを失うことなく、冗長性を減らすための追加の最適化や方法を愛しています。
try/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」をインスタンス化すると「oops」が出力されます。
@ roman-borisovに類似したアプローチですが、より型保証されています。
case class ShortException(message: String = "", cause: Option[Throwable] = None)
extends Exception(message) {
cause.foreach(initCause)
}
その後、あなたは、Java的に例外を作成することができます。
throw ShortException()
throw ShortException(message)
throw ShortException(message, Some(cause))
throw ShortException(cause = Some(cause))
は例外がのRuntimeExceptionを拡張するべきではないのですか? – opensas
さらに、ケースクラスとして宣言すれば、 "new"を取り除くことができます... – opensas
@opensas 'object MyException {def apply(message:String = null、cause:Throwable = null)= new MyException(メッセージ、原因)} 'で十分です。 – senia