Java 7のクロージャ(BGGA版)のプロトタイプを試してみた
Java API、使ってますか? (53) Java SE 7の要注目機能"クロージャ"はどうなるのか
の記事を参考に、ここからプロトタイプ実装をダウンロードしてきてインストールしてみた。
注意点として、上記の紹介記事ではJDK 5.0以降が必要という風に書かれているが、JDK 5.0だと次のようにUnsupportedClassVersionErrorが出てコンパイラが実行できなかった(JDK 6.0だと動作することは確認)。
Error occurred during initialization of VM java/lang/UnsupportedClassVersionError: Bad version number in .class file
さて、早速、まずは上記リンク先の紹介記事に書かれているコードをコンパイルしてみた。
>bin\javac FirstClosure.java
コンパイルは無事に成功し、以下のファイルが生成された。
FirstClosure.class FirstClosure$1.class javax\lang\function\I.class javax\lang\function\OO.class javax\lang\function\unrestricted\I.class javax\lang\function\unrestricted\OO.class
実行してみる。
>bin\java FirstClosure 1234
次は、定番の(?)map関数を定義してみる。
import java.util.*; public class MapFunction { public static <A, B> List<B> map({A => B} fn, List<A> list) { List<B> newList = new ArrayList<B>(); for(A a:list) newList.add(fn.invoke(a)); return newList; } public static void main(String[] args) { List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); System.out.println(map({Integer n => n * 2}, list)); } }
コンパイル。
>bin\javac MapFunction.java
実行。
>bin\java MapFunction [2, 4, 6, 8, 10]
とりあえず、BGGA版のクロージャ(というか無名関数)は、記法は違うものの、慣れればScalaの無名関数と同じような感じで使えそう(当たり前だが)。ただ、Scalaと比べた場合、無名関数の引数の型を省略できないのが、ちょっと嫌かも。
追記:Rubyなどにある、ブロックの実行が終わったら必ず閉じるopenのようなものも実装してみた。
import java.io.*; import static java.lang.System.*; public class ClosingResource { public static <T, throws E> T open( String filePath, {Reader => T throws E} block ) throws FileNotFoundException, E { FileReader reader = new FileReader(filePath); try { return block.invoke(reader); } finally { try { out.printf("closing %s...%n", filePath); reader.close(); } catch (IOException ex) { ex.printStackTrace(); } } } public static void main(String[] args) throws Exception { String result = open( "input.txt", {Reader r => out.println("read started"); StringBuilder buf = new StringBuilder(); for(int ch; (ch = r.read()) != -1;) buf.append((char)ch); out.println("read finished"); new String(buf) } ); System.out.println(result); } }
例外に対して透過にするために
コンパイル。
>bin\javac ClosingResource.java
実行。
>bin\java ClosingResource read started read finished closing input.txt... a b c
input.txtの内容:
>type input.txt a b c