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の詳細については こちら