memo

ちょっとしたメモ書き(個別表示)

Javaでクロージャもどき : (2006/06/24)
Javaの無名クラスを使ってみた例
block.java
かなり冗長だけど、クロージャっぽく見えなくもない
RVector v = new RVector();

v.addElement("first");
v.addElement("second");
v.addElement("third");
v.addElement("fourth");
v.addElement("fifth");

final String tail = " element";

v.filter(new RBlock_boolean() {
public boolean call(Object x) {
return (((String)x).toCharArray()[0] == 'f');
}
}).collect(new RBlock() {
public Object call(Object x) {
return ((String)x) + tail;
}
}).foreach(new RBlock_void() {
public void call(Object x) {
System.out.println(x);
}
});


RBlockインターフェースのcallメソッドを実装した無名クラスを作り、そのインスタンスを渡すことでRubyのイテレータっぽい書き方をしてる。
RVectorはVectorを継承しており、追加された各メソッドに関しては

filter 全要素を走査し、与えられたインスタンスのcallメソッドが真を返した物のみを集めたRVectorインスタンスを作る
collect 全要素を走査し、与えられたインスタンスのcallメソッドを適用した結果を集めたRVectorインスタンスを作る(自分自身は変化しない)
map 全要素を走査し、与えられたインスタンスのcallメソッドを適用した結果で置き換える(自分自身を書き換える)
foreach 全要素を走査し、与えられたインスタンスのcallメソッドを適用する


ただし、見てのとおりかなり冗長なので、個人的にはプリプロセッサを書いて、以下のようなコードを上記のようなコードに展開したい(戻り値の型を省略すると、Object型とする)
なんだか既存の構文と衝突しているような気もするけど気にしない


String tail = "_tail";

v.filter(boolean { | x |
return (((String)x).toCharArray()[0] == 'f');
}).collect({ | x |
return ((String)x) + tail;
}).foreach(void { | x |
System.out.println(x);
});


ますますソレっぽい
見た目はRubyのブロックっぽいけど、この例では単に無名クラスのインスタンスを生成してるだけなので、Rubyのブロックと違って持ち歩ける
(というより、Rubyのあれはクロージャのサブセットなのか)

rblock.Void b = void { | x | System.out.println(x); };

vector1.foreach(b);
vector2.foreach(b);

場合によっては便利かもしれないかもしれない

とりあえずファイルを置いておきましょうか
jpp.060625c.tar.gz
ファイルを展開したあと、jpp.plを実行してください
(事前にjavacにPATHを通しておいてください)
tar xvfz jpp.xxxxxx.tar.gz
cd jpp
./jpp.pl block.java
java HelloWorld

(注)この記事をあまり真に受けないこと
ちなみに、この記事のコードはJDK1.4系用(JDK1.5系はコンテナの仕様が変わってる)

: back