web-dev-qa-db-ja.com

例外はケースクラスである必要がありますか?

カスタム例外タイプはcase classesにする必要がありますか?

プラス面では、私は抽出器を手に入れます。

マイナス面として、私は間違った平等セマンティクスを取得します。しかし、equalsをオーバーライドすることでそれを回避できます。

では、概念レベルで、それらをcase classesにすることは理にかなっていますか?

47
missingfaktor

もちろんこれは非常に主観的ですが、私の意見では、ケースクラスとして例外クラスを用意することをお勧めします。主な理由は、例外をキャッチするとパターンマッチングを実行し、ケースクラスをパターンマッチングで使用する方がはるかに優れているということです。ケースクラス例外を使用する場合に、catchブロックでパターンマッチングの全機能を使用する機能を利用する例を次に示します。

_object IOErrorType extends Enumeration {
  val FileNotFound, DeviceError, LockedFile = Value
}
case class IOError(message: String, errorType: IOErrorType.Value) extends  Exception(message)

def doSomeIO() { throw IOError("Oops, file not found!", IOErrorType.FileNotFound)  }

try {
  doSomeIO()
} catch {
  case IOError( msg, IOErrorType.FileNotFound ) =>
    println("File not found, please check the path! (" + msg + ")")
}
_

この例では、例外が1つだけありますが、発生した正確なエラータイプを知りたい場合に備えて、errorTypeフィールドが含まれています(通常、これは例外の階層によってモデル化されていますが、これは言っていません)良くも悪くも、例は単なる例示です)。 IOErrorはケースクラスであるため、case IOError( msg, IOErrorType.FileNotFound )を実行するだけで、エラータイプ_IOErrorType.FileNotFound_の例外のみをキャッチできます。ケースクラスで無料で入手できるエクストラクタがないと、毎回例外をキャッチし、実際に興味がない場合に備えて再スローする必要があります。これは間違いなくより冗長です。

あなたは、ケースクラスがあなたに間違った平等セマンティクスを与えると言います。私はそうは思いません。 Yo、例外クラスの作成者が、どの等価セマンティクスが意味をなすかを決定するようになります。結局のところ、例外をキャッチするとき、catchブロックは、通常はタイプのみに基づいてキャッチする例外を決定する場所ですが、私の例のように、そのフィールドの値などに基づくこともできます。重要なのは、例外クラスの同等性セマンティクスはそれとはほとんど関係がないということです。

36

例外ケースクラスを作成することによって失われる一般的なイディオムの1つは、エラー条件のより高い特異性を示すために使用されるサブクラス化を使用して、例外のサブクラス階層を作成するパターンです。ケースクラスをサブクラス化することはできません。

18
Dave Griffith

レジス・ジャン・ジルの答えが好きです。ただし、ケースクラスを作成しない正当な理由がある場合(Dave Griffithの回答を参照)、通常のクラスを使用して上記のサンプルと同じようにアーカイブし、適用を解除できます。

object IOErrorType extends Enumeration {
  val FileNotFound, DeviceError, LockedFile = Value
}
object IOError {
  def unapply(err: IOError): Option[(String, IOErrorType.Value)] = Some(err.message, err.errorType)
}
class IOError(val message: String, val errorType: IOErrorType.Value) extends  Exception(message)

def doSomeIO() { throw new IOError("Oops, file not found!", IOErrorType.FileNotFound) }

try {
  doSomeIO()
} catch {
  case IOError( msg, IOErrorType.FileNotFound ) =>
    println("File not found, please check the path! (" + msg + ")")
}
4
dev-null