Java 7のクロージャ(BGGA版)のプロトタイプを試してみた(3) - closure conversion
参考URLはこの辺:http://tronicek.blogspot.com/2007/12/closure-conversion.html
BGGAのクロージャには、クロージャを互換性のあるインタフェース型に自動的に変換するclosure conversionという機能がある。ここで、互換性のあるインタフェース型というのは、
- メソッドを一つだけ持っており
- そのメソッドの返り値の型および引数の型がクロージャの型と互換性がある
という条件を満たしていれば良いようだ。
たとえば、
interface F {
int apply(int arg);
}というインタフェースがあったとすると、
F pow2 = {int arg => arg * arg};という風に書くことができる。実際に以下のコードを書いて、
public class ClosureConversions1 {
interface F { int apply(int arg); }
public static void main(String[] args) {
F pow2 = {int arg => arg * arg};
System.out.printf("pow2(%d) = %d%n", 3, pow2.apply(3));
}
}実行してみると、
>java ClosureConversions1 pow2(3) = 9
のようになり、意図通りにクロージャがF型のインスタンスに変換されていることがわかる。
既存のJavaライブラリでは、しばしばメソッドを1つだけ持ったインタフェース型がfunction typeの代替のような感じで使われているため、closure conversionを使えば、そのような既存のライブラリを呼び出すときに、無名クラスを使うのに比べてより簡潔に記述することができる。
たとえば、java.ioパッケージには、FileFilterというインタフェースがあって、この型のオブジェクトをjava.io.File#listFiles(FileFilter filter)メソッドに引数として渡すことで、ディレクトリからファイルの一覧を取得するときに、ディレクトリの全要素を取得するのではなく、条件を満たした要素のみを取得するようにできるが、ここで、インタフェースFileFilterは
boolean accept(File pathname)
というたった一つのメソッドを持っているため、closure conversionを使うことができる。
というわけで、java.io.File#listFiles(FileFilter filter)メソッドの呼び出しを、closure conversionを利用して書いたのが、以下のコード。
import java.io.*;
public class ClosureConversions2 {
public static void main(String[] args) {
File[] files = new File(".").listFiles(
{File file => file.getName().endsWith(".java")}
);
for(File f:files) System.out.println(f.getName());
}
}実行結果。
>java ClosureConversions2 ClosureConversions1.java ClosureConversions2.java