try/catch or throws しなきゃいけないとき

後輩に聞かれたので書いてみる。

Javaクラスはそのクラスが投げるチェック済み例外をすべて、メソッド・シグニチャーの中で宣言する必要があり、またタイプEのチェック済み例外を投げるメソッドを呼ぶメソッドはどれも、Eを捉えるか、同じくE(またはEのスーパークラス)を投げるとして宣言する必要があります。こうすることでJava 言語は、制御がメソッドから出る方法として想定できるものをすべて、強制的に文書化させるのです。

Javaの理論と実践: 例外をめぐる議論

というわけです。というのも寂しいし、なんとも固い感じなのでもうちょっと噛み砕いてみる。


自分が呼び出しているメソッドで例外が投げられる場合、自分が書いているメソッドでその例外を捉えるか、例外を投げる宣言をする必要がある。


具体的に SimpleDateFormat を例にして考えてみる。
SimpleDateFormat の format メソッドを使う場合、例外処理は必要ない。
でも parse メソッド を使うときは try/catch or throws しないとコンパイラに怒られる。

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Sample {
    public static void main(String[] args) {
        SimpleDateFormat sdf = new SimpleDateFormat();
        sdf.applyPattern("yyyy/MM/dd");

        String dateStr = sdf.format(new Date());

        try {
            Date date = sdf.parse("2009/01/01");
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}

Javadoc でそれぞれのメソッドを確認してみる。
SimpleDateFormat の format(Date date) と parse(String source) は親クラスである DateFormat で宣言されている。
# 例も DateFormat でよかったじゃないか…ここまで書いてしまったので気にせず進む。

format
public final String format(Date date)
Date を日付/時刻文字列にフォーマットします。
パラメータ:
date - 時刻文字列にフォーマットする時刻値
戻り値:
フォーマットされた時刻文字列

http://java.sun.com/javase/ja/6/docs/ja/api/java/text/DateFormat.html#format(java.util.Date)

parse
public Date parse(String source)
throws ParseException
指定された文字列の先頭からテキストを解析して日付を生成します。メソッドは指定された文字列のテキスト全体に使用されない場合もあります。
日付の解析についての詳細は、parse(String, ParsePosition) メソッドを参照してください。
パラメータ:
source - 先頭が解析される String
戻り値:
文字列から解析される Date
例外:
ParseException - 指定された文字列の先頭が 解析できない場合

http://java.sun.com/javase/ja/6/docs/ja/api/java/text/DateFormat.html#parse(java.lang.String)

parse メソッドでは throws ParseException となっている。
というわけで、parse メソッドを使う場合、try/catch or throws が必要になる。

最初の引用に戻る。

Javaクラスはそのクラスが投げるチェック済み例外をすべて、メソッド・シグニチャーの中で宣言する必要があり、またタイプEのチェック済み例外を投げるメソッドを呼ぶメソッドはどれも、Eを捉えるか、同じくE(またはEのスーパークラス)を投げるとして宣言する必要があります。こうすることでJava 言語は、制御がメソッドから出る方法として想定できるものをすべて、強制的に文書化させるのです。

Javaの理論と実践: 例外をめぐる議論

「タイプEのチェック済み例外を投げるメソッド」というのは ParseException を投げる parse メソッドになる。
続いてそれを「呼ぶメソッド」は、main メソッドになる。
というわけで、 main メソッドは ParseException を捉える(try/catch)するか、ParseException(あるいはスーパークラス)を投げる宣言(throws ParseException)をしなくてはならない。


自分が作るクラスやメソッドによって、try/catch するか、throws するかは変わってくる。
try/catch するか、throws するかというのは、なかなか難しい問題なので、またいつかどこかで。