TL;DR
コンパイラは、それがスローFileNotFoundException()
される唯一のものではない可能性があると見なします。Exception
説明
JLS§11.2.3 例外チェック
catch 句が (§11.2) チェック済み例外クラス E1 をキャッチでき、catch 句に対応する try ブロックがチェック済み例外クラス E2、E1 のサブクラス、および前の catch 句をスローできる場合、Java コンパイラは警告を発行することが推奨されます。すぐ外側の try ステートメントは、E2 <: E3 <: E1 であるチェック済み例外クラス E3 をキャッチできます。
つまり、catch ブロックによってスローされる可能性のある唯一の例外が であるとコンパイラが判断した場合、FileNotFoundException()
2 番目の catch ブロックについて警告が表示されます。ここではそうではありません。
ただし、次のコード
try{
throw new FileNotFoundException();
} catch (FileNotFoundException e){
e.printStackTrace();
} catch (IOException e){ // The compiler warns that all the Exceptions possibly
// catched by IOException are already catched even though
// an IOException is not necessarily a FNFException
e.printStackTrace();
} catch (Exception e){
e.printStackTrace();
}
これは、コンパイラが try ブロックを評価して、どの例外がスローされる可能性があるかを判断するために発生します。
コンパイラは警告を出さないためÈxception e
、他の例外がスローされる可能性があると見なされます (例: RunTimeException)。これらの RunTimeExceptions を処理するのはコンパイラの仕事ではないので、それを逃してしまいます。
答えの残りの部分は、例外キャッチの背後にあるメカニズムを理解するために読むのが興味深いです。
スキーマ
ご覧のとおり、は階層の上位にあるため、下位の階層Exception
の後に最後に宣言する必要があります。IOException

例
IOException
投げられたと想像してください。から継承されているException
ため、IOException IS-A Exception と言えます。そのため、常にブロック内でキャッチされ、Exception
ブロックIOException
に到達できなくなります。
実際の例
たとえば、あなたが店にいて、ズボンを選ばなければならないとしましょう。売り手は、最大のものから最小のものまで試してみなければならないとあなたに言います.
自分のサイズに対して大きすぎるパンツを買ってしまうと、自分に合うパンツを見つける機会がなくなります。
別の店に行くと、そこでは正反対のことが起こっています。ズボンは小さいものから大きいものまで選べます。
あなたはあなたの正確なサイズでズボンを買うことに気付くでしょう.
それは少し類推で、少し奇妙ですが、それ自体が物語っています。
Java 7 以降、try ブロックによってスローされる可能性のあるすべてのタイプの例外を 1 つの唯一の catch ブロック内に含めるオプションがあります。
警告 : 階層も尊重する必要がありますが、今回は左から右の順です。
あなたの場合、それは
try{
//doStuff
}catch(IOException | Exception e){
e.printStackTrace();
}
次の例は、Java SE 7 以降で有効であり、重複したコードを排除します。
catch (IOException|SQLException ex) {
logger.log(ex);
throw ex;
}
catch 句は、ブロックが処理できる例外の種類を指定し、各例外の種類は縦棒 (|) で区切られます。