Code Fix

上級

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  }
Main.java:5: error: unreported exception IOException; must be caught or declared to be thrown

検査例外は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  }
Main.java:5: error: ';' expected

例外を受け取るブロックは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  }
Main.java:8: error: exception IOException is never thrown in body of corresponding try statement

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  }
Main.java:7: error: exception FileNotFoundException has already been caught

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  }
Main.java:7: error: unreported exception IOException; must be caught or declared to be thrown

try-with-resourcesはブロックを抜けるときに自動でclose()を呼びます。close()が投げる検査例外も、通常のthrowと同じく宣言や捕捉が必要です。

直し方: (空) を throws IOException にします。

この問題を解いてみる →

よくある誤解

catchして握りつぶすのは「対処」ではありません。その場で対処できないなら、throwsで上に投げるほうが正しい場面が多いです。

実務での勘所

検査例外(checked exception)は実はJava特有の設計実験です。C#やKotlin、Pythonなど後発の主要言語の多くは、意図的に検査例外を採用していません。理由は、呼び出し元に対応を強制する仕組みが、catchして何もしない(握りつぶす)という誤った対処を誘発しやすいことが分かってきたためです。Java自身も、Stream APIのようなJava 8以降の新しいAPIでは検査例外を扱いにくくなっており、言語設計として距離を置きつつあります。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)