LoginSignup
12
9

More than 5 years have passed since last update.

Java9の新try-with-resources

Last updated at Posted at 2018-07-26

こんにちは。

Java7から導入されたtry-with-resources。イイですよね、便利ですネ簡素にかけますネ。
しかも、Java9になると、さらにスマートな書き方が導入されました。
だ...だけど、ちょっとハマるというか、残念なことがあったので、記事にしてみました。

まずは、Java7とJava8のtry-with-resourcesの書き方

書籍「Effective Java -Third Edition-(Joshua Bloch著)」の36ページに掲載されてあるfirstLineOfFileメソッドを、ここに掲載します。mainメソッドは私のオリジナルです。

Java7と8のtry-with-resources
public class Java7and8TryWithResources {
    public static void main(String[] args) {
        String val = firstLineOfFile("test.txt", "-------");
        System.out.println(val);
    }

    static String firstLineOfFile(String path, String defaultVal) {
        try (BufferedReader br = new BufferedReader(new FileReader(path))) {
            return br.readLine();
        } catch (IOException e) {
            return defaultVal;
        }
    }
}

この書籍、Java9についても対応したよ!と謳い文句にあるのですが、try-with-resourcesに関しては上記のサンプルコードを掲載したどまりでおしまい。ちょっと残念。

Java9から書けるようになった新try-with-resources構文

Java9から書けるようになった新try-with-resources構文では、変数宣言はtry()の中ではなく、try構文の前で書けるようになりました。

Java9の新try-with-resources構文
public class Java9NewTryWithResources {
    public static void main(String[] args) {
        String val = "-------";
        try {
            val = firstLineOfFile("test.txt", val);
        } catch (FileNotFoundException e) {
            // 略
        }
        System.out.println(val);
    }

    static String firstLineOfFile(String path, String defaultVal) throws FileNotFoundException {
        BufferedReader br = new BufferedReader(new FileReader(path)); // ここ注目!😲
        try (br) { // ここも注目!😲
            return br.readLine();
        } catch (IOException e) {
            return defaultVal;
        }
    }
}

さて、この新構文ですが、オフィシャルな出典を探そうと試みました。
More concise try-with-resources statements in JDK 9
ブログなのですが、ここはURLがoracle.comなので、一応公式なのかな、と。

【1日遅れで追記】オフィシャルな出典を見つけました。Java Language Changes for Java SE 9です。でも、すぐ上のブログと同じことしか書いてないや。

https://docs.oracle.com/javase/9/https://docs.oracle.com/javase/10/ も見たんですが、そこにリンク張ってある「Java Tutorials」が現在、

The Java Tutorials have been written for JDK 8. Examples and practices described in this page don't take advantage of improvements introduced in later releases.
(JavaチュートリアルはJDK 8向けに書かれています。このページで説明されている例とプラクティスは、それ以降のリリースで導入された改良点を利用していません。)

とあり、ズッコケ🤷です。そのうちJDK 9向けのチュートリアルが掲載されることを祈ります。:milky_way:

公式ではないところのサイトだと、

が見つかりました。

嬉しいことと、残念だと思うこと

上掲のJava9NewTryWithResources.javaとJava7and8TryWithResources.javaとを比較してみます。

嬉しいこと

うわっ…私のtry()の中、短すぎ…?! shock_woman.png

たったこれだけで、イイの?!イイんです。クゥ~!👍
BufferedReader br = new BufferedReader(new FileReader(path));
try (br) {

残念なところ

FileNotFoundExceptionをスローするnew FileReader(path)のせいで、以下の2点が残念に思います。

throws句が付いちゃったよ😧
static String firstLineOfFile(String path, String defaultVal) throws FileNotFoundException {
mainの中が行数増えたよ😩
String val = "-------";
try {
    val = firstLineOfFile("test.txt", val);
} catch (FileNotFoundException e) {
     // 略
}
System.out.println(val);

try-with-resourcesは何がために?

:musical_note:あなたと呼べば あなたと答える:notes:

みなさんご存知の名曲、ディック・ミネと星玲子の『二人は若い』の冒頭ですね。懐かしい。作詞はさすがサトウハチロー先生です。

それになぞらえて、私はこう歌ってしまいます。

:musical_note:「try」と呼べば「例外」と答える。:notes:

ところが!です。「try-with-resources」は、ただの「try」ではないのです。AutoClosableが為にあるのです。そこを失念してはいけません!
くだんのnew FileReader(path)にイチャモンを付けましたけど、だってこれ、try { … } の中に書いてないもん!BufferedReaderをオートクローズしてもらいたくてtry-with-resources書いたんだもん!

こんな書き方もできる

でも、FileReaderAutoClosableなんです。なので、以下のようにも書けます。

Java9NewTryWithResourcesを一部書き換えてみた
public class Java9NewTryWithResources2 {
    public static void main(String[] args) {
        String val = "-------";
        try {
            val = firstLineOfFile("test.txt", val);
        } catch (FileNotFoundException e) {
            // 略
        }
        System.out.println(val);
    }

    static String firstLineOfFile(String path, String defaultVal) throws FileNotFoundException {
        FileReader fr = new FileReader(path);
        BufferedReader br = new BufferedReader(fr);
        try (fr; br) { // 複数並べて書けます
            return br.readLine();
        } catch (IOException e) {
            return defaultVal;
        }
    }
}

これでもfirstLineOfFileメソッドにthrows FileNotFoundExceptionを付けざるをえないんですけどね。つまり、

コンストラクタ/メソッド 例外 どうする?
BufferedReaderのコンストラクタ 例外をスローしない try-with-resourcesでオートクローズしてもらうだけでOK
FileReaderのコンストラクタ FileNotFoundExceptionをスローする メソッドのシグネチャにthrows付ける
BufferedReaderreadLineメソッド IOExceptionをスローする catchする

この三者三様に気づかないと、「え?なんでbrはくて、frはダメなの?」とか、「何が為のIOExceptionをキャッチ?しかもFileNotFoundExceptionってIOExceptionのサブクラスだし...」などとヤキモキしてしまうことになります。

まとめ

Java9の新try-with-resources構文、いんだか悪いんだか。悩みます。まとめになってなくて、すみません。🙇

以上です。

12
9
6

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
9