第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()); }
実装に当たっては、Scanner
とPrintWriter
両方がオープンされた場合に両方のリソースをきちんとクローズすること。
この中には、Exception
がスローされる個所が7つある。
Scanner
のコンストラクタPrintWriter
のコンストラクタScanner
のhasNext
メソッドScanner
のnext
メソッドPrintWriter
のprintln
メソッドScanner
のclose
メソッドPrintWriter
のclose
メソッド
ちょっと待った!
この問題は間違っている。
Scanner
とPrintWriter
クラスは、ほとんどのメソッドでチェック例外をスローしない。
Scanner
クラスは、内部に持っているReadable
オブジェクトがスローする例外を、PrintWriter
クラスは、内部に持っているWriter
オブジェクトがスローする例外を、隠蔽している。
そこで、各クラスは隠蔽した例外を公開するためにScanner#ioException
とPrintWriter#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(); }
ただし、次の練習問題のために、抑制された例外には対応していない。