てっとり早くGroovyでJava8のLambdaを使う
groovy 2.3以降、Goovyクロージャはfunctinal interface(sum型)が要求される場所で使用される場合、自動的にそのインターフェースに変換されるようになりました。
Groovy-MLで議論も始まっており、Groovyは将来的にはJava8正式対応するかと思いますが、世の中ではJava8アーリーアクセス版とかで話題になってるので、試してみました。
シンタックスのレベルでは、当然GroovyはLambda式を扱えませんが(決まってないし!)、Lambda式の実装がSAM型のサブクラスのインスタンスであることを踏まえると、以下のように例えばExpandoMetaClassでアダプタを定義してやれば、クロージャでJava8のStreamを叩けるわけです。
import java.util.function.* import java.util.stream.Stream class StreamTest { static test01() { List<String> names = ["hoge hoge", "foo bar", "junji", "uehara"] names.forEach{ println it } } static test02() { List<String> names = ["hoge hoge", "foo bar", "junji", "uehara"] names.stream() .filter { it.length() > 5} .map {"[" + it + "]"} .forEach{ println it } } static main(args) { Iterable.metaClass.forEach = { Closure clos -> delegate.forEach(new Consumer(){ void accept(arg){ clos.call(arg) }}) } Stream.metaClass.forEach = { Closure clos -> delegate.forEach(new Consumer(){ void accept(arg){ clos.call(arg) }}) } Stream.metaClass.filter = { Closure clos -> delegate.filter(new Predicate(){ boolean test(arg){ clos.call(arg) }}) } Stream.metaClass.map = { Closure clos -> delegate.map(new Function(){ Object apply(arg){ clos.call(arg) }}) } test01() test02() } }
もちろんこんなことしなくても上のレベルはGroovyだけでできるし、無限長コレクションを使いたければGroovy Stream(github)というのもあるんだけど、上はあくまでJdkのAPIのStreamをGroovyのクロージャで利用している、というところがポイントです。
先のMLでの議論にあるように、クロージャとLambda式では得失がある*1ので、将来のGroovyにおいて、クロージャとLambda式が併存するのか、クロージャに一本化するべきなのか、その逆か、実装は、などはこれからの議論ということになるのでしょう。
使用したJava8のバージョンは
java full version "1.8.0-ea-lambda-nightly-h4200-20130429-b88-b00"
です。
参考: