unreported exception must be caught の原因と直し方
検査例外と非検査例外の境界。throwとthrowsの違い、catchできない型の条件を扱います。
エラーメッセージの読み方
Main.java:5: error: unreported exception IOException;
Main.java- ファイル名
5- 行番号 — javacが異常に気づいた位置。原因の行とは限りません
error- 種別 — コンパイルエラー。実行まで到達しません
unreported exception IOException;- 内容 — javacが期待していたもの、または見つけられなかったもの
このエラーが出る典型パターン
パターン1
1 import java.io.IOException; 2 3 public class Main { 4 public static void main(String[] args) { ^ 5 throw new IOException("boom"); 6 } 7 }
検査例外はtry-catchで捕まえるか、throwsで宣言する必要があります。throwは動作、throwsは宣言です。
直し方: (空) を throws IOException にします。
パターン2
1 public class Main { 2 public static void main(String[] args) { 3 try { 4 Thread.sleep(10); 5 } catches (InterruptedException e) { ^ 6 System.out.println("interrupted"); 7 } 8 } 9 }
例外を受け取るブロックはcatchです。Javaにexceptというキーワードはありません。
直し方: catches を catch にします。
パターン3
1 import java.io.IOException; 2 3 public class Main { 4 public static void main(String[] args) { 5 try { 6 int[] a = new int[1]; 7 System.out.println(a[5]); 8 } catch (IOException e) { ^ 9 System.out.println("caught"); 10 } 11 } 12 }
try内で発生しない検査例外は捕まえられません。非検査例外なら書けますが、型が合わなければ捕捉されません。
直し方: IOException を ArrayIndexOutOfBoundsException にします。
パターン4
1 public class Main { 2 public static void main(String[] args) { 3 try { 4 throw new java.io.FileNotFoundException("x"); 5 } catch (java.io.IOException e) { ^ 6 System.out.println("io"); 7 } catch (java.io.FileNotFoundException e) { 8 System.out.println("fnf"); 9 } 10 } 11 }
FileNotFoundExceptionはIOExceptionのサブクラスです。先にIOExceptionで捕まえると、後のcatchは絶対に実行されないため、コンパイルエラーになります。
直し方: java.io.IOException を NullPointerException にします。
パターン5
1 import java.io.*; 2 3 public class Main { 4 static class MyRes implements Closeable { 5 public void close() throws IOException { throw new IOException("x"); } 6 } 7 public static void main(String[] args) { ^ 8 try (MyRes r = new MyRes()) { 9 System.out.println("ok"); 10 } 11 } 12 }
try-with-resourcesはブロックを抜けるときに自動でclose()を呼びます。close()が投げる検査例外も、通常のthrowと同じく宣言や捕捉が必要です。
直し方: (空) を throws IOException にします。
よくある誤解
catchして握りつぶすのは「対処」ではありません。その場で対処できないなら、throwsで上に投げるほうが正しい場面が多いです。
実務での勘所
検査例外(checked exception)は実はJava特有の設計実験です。C#やKotlin、Pythonなど後発の主要言語の多くは、意図的に検査例外を採用していません。理由は、呼び出し元に対応を強制する仕組みが、catchして何もしない(握りつぶす)という誤った対処を誘発しやすいことが分かってきたためです。Java自身も、Stream APIのようなJava 8以降の新しいAPIでは検査例外を扱いにくくなっており、言語設計として距離を置きつつあります。