Javaコンパイラは、メソッドが例外をスローしない場合に、メソッド宣言でスローを許可する理由を知りたいと思います。「スロー」は、例外を処理する方法(呼び出し側に処理を通知する)なので) 。
例外を処理する方法が2つあるため(スローとtry/catch)。 try/catchでは、tryブロックでスローされない例外のキャッチは許可されませんが、例外をスローしない可能性のあるメソッドでのスローは許可されます。
private static void methodA() {
try {
// Do something
// No IO operation here
} catch (IOException ex) { //This line does not compile because
//exception is never thrown from try
// Handle
}
}
private static void methodB() throws IOException { //Why does this //compile when excetion is never thrown in function body
//Do Something
//No IO operation
}
throws
句は、メソッドの規約の一部です。メソッドの呼び出し元は、指定された例外がメソッドによってスローされる可能性があるように動作する必要があります(つまり、例外をキャッチするか、独自のthrows
句を宣言します)。
メソッドの初期バージョンはthrows
句で指定された例外をスローしない可能性がありますが、将来のバージョンはAPIを壊すことなくそれをスローできます(つまり、メソッドを呼び出す既存のコードは引き続きコンパイルに合格します) 。
反対も可能です。メソッドがthrows
句で指定された例外をスローするために使用されていたが、将来のバージョンではそれをスローしない場合、既存のコードを壊さないためにthrows
句を保持する必要がありますそれはあなたの方法を使用します。
最初の例:
methodB
を使用する次のコードがあるとします。
private static void methodA() {
methodB(); // doesn't have throws IOException clause yet
}
後でmethodB
を変更してIOException
をスローする場合、methodA
はコンパイルのパスを停止します。
2番目の例:
methodB
を使用する次のコードがあるとします。
private static void methodA() {
try {
methodB(); // throws IOException
}
catch (IOException ex) {
}
}
将来のバージョンのthrows
からmethodB
句を削除すると、methodA
はコンパイルをパスしなくなります。
この例は、methodA
がprivate
である場合、ローカルでは(同じクラス内で、それを呼び出すすべてのメソッドを簡単に変更できるため)使用できるため、あまり興味深いものではありません。
ただし、それがpublic
になると、誰がそのメソッドを使用するか(または使用するか)がわからないため、throws
句。
そして、それがインスタンスメソッドである場合、例外をスローしなくてもthrows
句を許可する別の理由があります-メソッドはオーバーライドでき、オーバーライドするメソッドは、基本クラスの実装であっても例外をスローする場合がありますではない。
シグネチャはメソッドのコントラクトを定義するためです。メソッドが今すぐIOExceptionをスローしない場合でも、将来的にはその可能性があり、その可能性に備える必要があります。
ここでは、メソッドのダミー実装を提供するだけで、後で実際の実装がIOExceptionをスローする可能性があることを知っているとします。コンパイラーがこのthrows節を追加できない場合、メソッドの実際の実装を提供すると、そのメソッドへのすべての呼び出しを(再帰的に)やり直す必要があります。
キーワードスローは、メソッドでIOExceptionが発生している可能性があることをプログラマに通知します。ここで、try/catchを指定しなかった場合は、例外がスローされるとプログラムが機能しなくなりますが、try/catchでは、例外がスローされた場合に何かを実行して処理します。
読みやすさのためにスローを使用し、例外の可能性を指定し、try/catchを使用して、例外の場合に何をすべきかをプログラムに伝えます。