【コラム】
本連載では過去数回に渡って、Java SE 7で導入される予定となっているJavaのクロージャについて、Closures for the Java Programming Languageで公開されているプロトタイプの仕様や実装をベースに解説している。プロトタイプ実装は逐次更新されており、仕様との差異も生じているので注意してほしい。たとえばエンクロージャのローカル変数に指定する@Sharedアノテーションや今回紹介するUnrestricted closureの「==>」などはまだ仕様には掲載されていない。これらは今後の仕様のアップデートにおいて反映させるとのことだ。
BGGA版の仕様では、通常のクロージャとは別に「Unrestricted closure」と呼ばれるものが定義されている。Unrestricted closureではcontinueやbreakで繰り返し処理を抜けたり、returnでエンクロージャの処理を終了したりすることが可能。Unrestricted closureは「=>」ではなく「==>」を用いて定義する。
たとえばリスト1のようなコードの場合、sample()メソッドの第1引数に渡された値が0だったらreturnで処理を抜ける。その結果、3回目のsample()呼び出しは実行されない。なおUnrestricted closureは実装が完了したばかりのため、最新版の実装でなければこのコードはコンパイルできない。
class UnrestrictedClosure {
static void sample(int number, { int ==> void } block) {
block.invoke(number);
}
public static void main(String[] args) {
{ int ==> void } unrestricted =
{ int num ==>
if (num == 0) return;
System.out.println(num); };
sample(10, unrestricted);
sample(0, unrestricted);
sample(20, unrestricted);
}
}
もし上記のクロージャを通常通り「=>」で宣言した場合(すなわちUnrestrictedにしなかった場合)、次のようなコンパイルエラーになるはずだ。
UnrestrictedClosure.java:5: 'return' not allowed in a restricted closure
if (num == 0) return;
^
BGGAのクロージャには「Control invocation syntax」と呼ばれるシンタックスシュガーが用意されている。これは、クロージャを引数に取るようなメソッドを簡潔に呼び出せるようにするためのものである。Control invocation syntaxは、最後の引数がUnrestricted closureであるメソッドの呼び出しに対して適用できる。
たとえば、リスト2に示すようなメソッドを定義したとする。このメソッドは唯一の引数(すなわち最後の引数)としてUnrestricted closureを受け取る。
static void sample({ ==> void } block) {
block.invoke();
}
通常の方法でこのメソッドを呼び出す場合はリスト3のようになるだろう。
sample({ ==> System.out.println("Hello!"); });
Control invocation syntaxを利用することで、この呼び出しをリスト4のように記述することができる。
sample() {
System.out.println("Hello!");
}
なおメソッドが複数の引数を受け取る場合には、クロージャである最後の引数以外はリスト5のような具合に通常通り記述すればよい。
static void sample(int x, int y, { ==> void } block) {
block.invoke();
}
sample(10, 20) {
System.out.println("Hello!");
}
Unrestricted closureが引数を受け取る場合には、まずクロージャ側の仮引数を列挙し、その後ろにコロンで区切ってメソッドに渡す値を指定する。リスト6はリスト1のsample()メソッドをControl invocation syntaxを利用して呼び出した例である。この例の場合、sample()メソッドには0が渡される。
class ControlInvocation3 {
static void sample(int number, { int ==> void } block) {
block.invoke(number);
}
public static void main(String[] args) {
sample(int num: 0) {
if (num == 0) return;
System.out.println(num);
}
}
}
Unrestricted closureとControl invocation syntaxを活用すれば、Javaの言語仕様にはない独自の制御構文をメソッドとして定義することも可能となる。具体的には、制御の対象となるコードをクロージャとして(最後の引数で)渡すメソッドを用意し、そのメソッド内で制御コードと共にinvokeが実行されるようにしておく。するとメソッドの呼び出し元ではControl invocation syntaxによってクロージャ部分がステートメントとして記述できるので、forやwhileなどの制御構文と同様の使い勝手が実現できるというわけだ。
BGGA版の仕様ではその具体例がいくつか掲載されている。例えば指定されたロック機構で排他処理を行うwithLockだ。withLockメソッドの定義はリスト7のようになる。
このwithLockメソッドは第2引数で渡されたクロージャのinvoke()呼び出しの前に、第1引数で渡されたjava.util.concurrent.locks.Lockオブジェクトを用いてロックを取得する。そしてinvoke()の処理が終了したらロックの開放を行う。
public static T
withLock(Lock lock, { ==>T throws E } block) throws E {
lock.lock();
try {
return block.invoke();
} finally {
lock.unlock();
}
}
これを利用するにはControl invocation syntaxを利用してリスト8のように記述すればよい。実際にはSystem.out.printlnの部分がクロージャとして渡され、withLockメソッド内のinvoke()呼び出しによって実行されるため、この処理は指定されたLockオブジェクトによって排他制御されることになる。
Lock lock = new ReentrantLock();
withLock(lock) {
System.out.println("Under 'withLock' control.");
}
なお、このwithLockメソッドのControl invocation syntaxを利用しない場合の呼び出しはリスト9のようになる。
withLock(lock,
{ ==>
System.out.println("Under 'withLock' control.");
});
提供:マイナビ
大学・大学院・短大・専門学生向けの就職情報サイト「マイナビ2010」「マイナビ2009」に今すぐ登録しよう! 大手企業からベンチャー企業までの約13,000社の企業情報を公開、エントリーが可能です。2010年卒予定の方は「マイナビ2010」に、2009年卒予定の方は「マイナビ2009」に登録してください。
毎日コミュニケーションズはプライバシーマークを取得しています。
| 超新星残骸中にないはずの多量の一酸化炭素 - 天文衛星「あかり」が発見 [21:42 2/9] |
| 【レポート】ROBO-ONE委員会 - 第20回大会でのROBO-ONE Lightの開催を決定 [20:27 2/9] |
| 火星に海の存在を示す有力な証拠が発見される - ESAが発表 [18:48 2/9] |
| iOS向けSPDYライブラリが登場、普及はじまるSPDY [11:57 2/9] |
| GitHubのアクティブプロジェクト、もっとも多いのはMITライセンス [11:42 2/9] |
|
[長谷川博己]新人賞受賞で“ミタ”がキタ! 鈴木京香との熱愛は「ご想像にお任せ」 [06:00 2/10] エンタメ |
|
[AKB柏木由紀]「SDN48」ラストシングルMVにゲスト出演 メンバーの10年後の同窓会で再会 [05:00 2/10] ホビー |
|
大東駿介、改名後初の写真集発売--名前を変えたのは「自分の決意表明です」 [00:30 2/10] エンタメ |
|
悲しいけれど超ウマい!極貧芸能人が編み出した奇跡のアイデアレシピベストテン! [00:06 2/10] キャリア |
|
みんなが聴きたい女性アーティスト・ラブソングベスト30を思い出の映像と共に発表! [00:05 2/10] キャリア |