参考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