CUBは子供の白熊

Java SE 8 実践プログラミングの練習問題を解く

第9章 Java 7 の機能を復習する : 問題 1 : try-with-resources 文

問題

以下のコードを try-with-resources 文を使わないで実装せよ。

try (Scanner in = new Scanner(Paths.get("/usr/share/dict/words"));
     PrintWriter out = new PrintWriter("/tmp/out.txt")
    ) {
    while (in.hasNext())
        out.println(in.next().toLowerCase());
}

実装に当たっては、ScannerPrintWriter両方がオープンされた場合に両方のリソースをきちんとクローズすること。

この中には、Exceptionがスローされる個所が7つある。

  • Scannerのコンストラクタ
  • PrintWriterのコンストラクタ
  • ScannerhasNextメソッド
  • Scannernextメソッド
  • PrintWriterprintlnメソッド
  • Scannercloseメソッド
  • PrintWritercloseメソッド

ちょっと待った!

この問題は間違っている。

ScannerPrintWriterクラスは、ほとんどのメソッドでチェック例外をスローしない。
Scannerクラスは、内部に持っているReadableオブジェクトがスローする例外を、PrintWriterクラスは、内部に持っているWriterオブジェクトがスローする例外を、隠蔽している。
そこで、各クラスは隠蔽した例外を公開するためにScanner#ioExceptionPrintWriter#checkErrorメソッドを用意しているぐらいである。

■ 実際に発生する例外(イタリックは非チェック例外)

クラス メソッド 例外
Scanner コンストラクタ IOException
PrintWriter コンストラクタ FileNotFoundException
SecurityException
Scanner hasNext IllegalStateException
Scanner next NoSuchElementException
IllegalStateException
PrintWriter println なし
Scanner close なし
PrintWriter close なし

何のことはない、例外をスローするのはコンストラクタだけである。
closeメソッドが例外をスローしないんじゃ、try-with-resources 文のありがたみが薄れる。
Scanner, PrintWriterの替わりにBufferedReader, BufferedWriterを使うことにする。

■ try-with-resources 文を使った例

try (BufferedReader in = Files.newBufferedReader(Paths.get("/usr/share/dict/words"));
     BufferedWriter out = Files.newBufferedWriter(Paths.get("/tmp/out.txt"))
    ) {
    String line;
    while ((line = in.readLine()) != null) {
        out.write(line.toLowerCase());
        out.newLine();
    }
}

解答

try-with-resources 文を使わないとしたら、try-finally 句をネストすればよい。

■ try-with-resources 文を使わない

BufferedReader in = Files.newBufferedReader(Paths.get("/usr/share/dict/words"));
try {
    BufferedWriter out = Files.newBufferedWriter(Paths.get("/tmp/out.txt"));
    try {
        String line;
        while ((line = in.readLine()) != null) {
            out.write(line.toLowerCase());
            out.newLine();
        }
    } finally {
        out.close();
    }
} finally {
    in.close();
}

ただし、次の練習問題のために、抑制された例外には対応していない。