2011年7月23日土曜日

JavaSE7のtryは便利

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

2011年7月17日日曜日

Eclipse3.7 で JavaSE7

Eclipse3.7 で JavaSE7

JavaSE7の正式リリースは2011年7月28日で、NetBeansは既にJavaSE7に対応しています。
EclipseはまだJavaSE7に対応していないのですが、pluginをインストールすれば使えるようになります。

各ツールのサイト
Java™ Platform, Standard Edition 7 Developer Preview Release
Eclipse Classic 3.7
JDT/Eclipse Java 7 Support(BETA)
JDK準備
JDK7 Preview Releaseをダウンロードして、インストールします。
開発ツールだけインストールすればOKです。
Eclipse準備
Eclipseは3.7の「Classic」を使います。
「IDE for Java Developers」や、「IDE for Java EE Developers」では、pluginのインストールができませんでした。
Install New SoftWare -> Work with:
「http://build.eclipse.org/eclipse/java7patch/」を入力して、pluginをインストールします。
Eclipse設定
Preferences -> Java -> Installed JREs
インストールしたJDK1.7を追加し、使用するようにします。
あとは、Java Compilerの設定で、Compiler compliance level を 1.7 にすれば準備完了です。

実は、上記で設定した開発環境には問題があり、メソッドや変数の候補を出せなくなります。
普段から、何も考えずにとりあえず Ctrl + Space 押して幸せになっている私にとっては致命的です。
Eclipseで正式にサポートされるまではJavaSE7は我慢するか、NetBeansを使いましょう。