7月28日に正式リリースされるJavaSE7では、いくつか便利な構文が増えます。
今回は、その中でも特に有用であろうtryの新しい構文について調べてみました。
ファイルのコピーを例にして、tryの構文の拡張を調べてみます
JavaSE6以前のソースコードをJavaSE7のコードに置き換えます。
- これまで(JavaSE6以前)のコード
-
FileInputStream fis = null; FileOutputStream fos = null; try { fis = new FileInputStream("D:\\test.txt"); fos = new FileOutputStream("D:\\test2.txt"); byte[] bytes = new byte[1024]; int size = -1; while ((size = fis.read(bytes)) != -1) { fos.write(bytes, 0, size); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (fos != null) { try { fos.close(); } catch (IOException ex) { } } if (fis != null) { try { fis.close(); } catch (IOException ex) { } } }
これから、上記のソースコードをJavaSE7風に書き換えていきます。
- 例外のマルチキャッチ
- catchの部分をひとつにまとめることができます
-
FileInputStream fis = null; FileOutputStream fos = null; try { fis = new FileInputStream("D:\\test.txt"); fos = new FileOutputStream("D:\\test2.txt"); byte[] bytes = new byte[1024]; int size = -1; while ((size = fis.read(bytes)) != -1) { fos.write(bytes, 0, size); } } catch (FileNotFoundException | IOException e) { e.printStackTrace(); } finally { if (fos != null) { try { fos.close(); } catch (IOException ex) { } } if (fis != null) { try { fis.close(); } catch (IOException ex) { } } }
-
これで、例外処理時に同じコードを書かずに済みます。
また、「|」で複数の例外を指定した場合は、左の例外から評価されるようです。
これまでの構文のcatchで上に書いていた例外は、その順で左から書けばよいでしょう。つまり、Throwableを書く場合は、一番右です。
- AutoCloseableインターフェース
-
JavaSE7から、AutoCloseableというインターフェースが追加されます。
このインターフェースには、closeというメソッドがあります(ご存知のとおり、JavaSE6以前にもcloseメソッドはありますが、それをオーバーライドしている感じです)。このメソッドが「try-finallyの処理で勝手に呼ばれる」ようです。 AutoCloseableを利用するためのコードは下記の通りです。
-
try (FileInputStream fis = new FileInputStream("D:\\test.txt"); FileOutputStream fos = new FileOutputStream("D:\\test2.txt")) { byte[] bytes = new byte[1024]; int size = -1; while ((size = fis.read(bytes)) != -1) { fos.write(bytes, 0, size); } } catch (FileNotFoundException | IOException e) { e.printStackTrace(); }
-
tryの()の中ではセミコロンで区切ると、複数のAutoCloseableを並べて記述できるようです。
Stream関係のインターフェースはAutoCloseableのサブインターフェースになっているようです。
インターフェースを実装する際に、AutoCloseableを意識する必要はあまりないと思われます。ъ(゚Д゚)グッジョブ!!(JavaSE6以前のソースを書き換える場合は別)
※public void close() throws IOException => public void close() throws Exception というふうに変わります。
なにはともあれ、コード量がかなり減りました。ワーイヽ(゚∀゚)メ(゚∀゚)メ(゚∀゚)ノワーイ
- AutoCloseableを検証
-
実際に自分の眼で見て確認しました。
closeの順番と、実際に例外が起こった場合について。 -
public class Test { public static void main(String[] args) { new Test().start(); } void start() { try (AutoCloseableImpl1 ac1 = new AutoCloseableImpl1(); AutoCloseableImpl2 ac2 = new AutoCloseableImpl2()) { } } } class AutoCloseableImpl1 implements AutoCloseable { AutoCloseableImpl1() { System.out.println(getClass().getSimpleName()); } @Override public void close() { System.out.println(getClass().getSimpleName() + "#close()"); } } class AutoCloseableImpl2 implements AutoCloseable { AutoCloseableImpl2() { System.out.println(getClass().getSimpleName()); } @Override public void close() { System.out.println(getClass().getSimpleName() + "#close()"); } }
-
上記のプログラムを実行します。
実行結果は
AutoCloseableImpl1
AutoCloseableImpl2
AutoCloseableImpl2#close()
AutoCloseableImpl1#close()
closeが呼ばれており、closeする順番もオッケー。
ちなみに、AutoCloseableImpl2()コンストラクタで例外を投げた場合は、以下
AutoCloseableImpl1
AutoCloseableImpl1#close()
Exception in thread "main" java.lang.NullPointerException
・・・
期待通りです。
余談ですが、catchもfinallyもないtry構文が書けるようになりました。(内部的にはfinallyが存在しますが)
実は、JavaSE7にはjava.nio.file.Filesというクラスが追加されており、ファイルをコピーするだけなら、このクラスを使ったほうが良いです。
まぁ、今回はあくまで勉強のためですから・・・
今回の検証でもちいたIDEはNetBeansです。
Eclipse3.7でも検証は可能でしたが、不都合な点がありましたので、NetBeansを使用しました。
現在のEclipse3.7とJDK1.7の詳細については こちら