【コラム】

Java API、使ってますか?

57 Java SE 7の要注目機能"クロージャ"はどうなるのか その5

57/60

Unrestricted closure

本連載では過去数回に渡って、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は実装が完了したばかりのため、最新版の実装でなければこのコードはコンパイルできない。

リスト1 UnrestrictedClosure.java - 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にしなかった場合)、次のようなコンパイルエラーになるはずだ。

プロンプト1 通常のクロージャではreturnできない

UnrestrictedClosure.java:5: 'return' not allowed in a restricted closure
                 if (num == 0) return;
                               ^

Control invocation syntax

BGGAのクロージャには「Control invocation syntax」と呼ばれるシンタックスシュガーが用意されている。これは、クロージャを引数に取るようなメソッドを簡潔に呼び出せるようにするためのものである。Control invocation syntaxは、最後の引数がUnrestricted closureであるメソッドの呼び出しに対して適用できる。

たとえば、リスト2に示すようなメソッドを定義したとする。このメソッドは唯一の引数(すなわち最後の引数)としてUnrestricted closureを受け取る。

リスト2 最後の引数がUnrestricted closureであるメソッドの例

    static void sample({ ==> void } block) {
        block.invoke();
    }

通常の方法でこのメソッドを呼び出す場合はリスト3のようになるだろう。

リスト3 通常の呼び出し

        sample({ ==> System.out.println("Hello!"); });

Control invocation syntaxを利用することで、この呼び出しをリスト4のように記述することができる。

リスト4 Control invocation syntaxを利用した呼び出し

        sample() {
            System.out.println("Hello!");
        }

なおメソッドが複数の引数を受け取る場合には、クロージャである最後の引数以外はリスト5のような具合に通常通り記述すればよい。

リスト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が渡される。

リスト6 クロージャが引数を取る場合の呼び出し

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()の処理が終了したらロックの開放を行う。

リスト7 withLockの定義例

    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オブジェクトによって排他制御されることになる。

リスト8 withLockを利用して排他処理を実行

    Lock lock = new ReentrantLock();
    withLock(lock) {
        System.out.println("Under 'withLock' control.");
    }

なお、このwithLockメソッドのControl invocation syntaxを利用しない場合の呼び出しはリスト9のようになる。

リスト9 Control invocation syntaxを利用しない場合

    withLock(lock, 
             { ==> 
                 System.out.println("Under 'withLock' control.");
             });

57/60

インデックス

連載目次
第60回 どうなる? 今後のJavaプラットフォーム(Java SE編)
第59回 どうなる? 今後のJavaプラットフォーム(Java EE編)
第58回 Java SE 7の要注目機能"クロージャ"はどうなるのか その6
第57回 Java SE 7の要注目機能"クロージャ"はどうなるのか その5
第56回 Java SE 7の要注目機能"クロージャ"はどうなるのか その4
第55回 Java SE 7の要注目機能"クロージャ"はどうなるのか その3
第54回 Java SE 7の要注目機能"クロージャ"はどうなるのか その2
第53回 Java SE 7の要注目機能"クロージャ"はどうなるのか
第52回 Early Draftが公開されたJSF 2.0
第51回 EJBから独立したJava Persistence 2.0
第50回 モバイルJavaの新しい潮流となるか - MSA 2.0のドラフト公開
第49回 やっぱり基本はServlet - Servlet 3.0のEarly Draftを読む
第48回 JOGLで3Dプログラミング その4
第47回 JOGLで3Dプログラミング その3
第46回 JOGLで3Dプログラミング その2
第45回 JOGLで3Dプログラミング
第44回 JARファイルを効率的にネットワーク転送するためのPack200形式
第43回 Early Draftで把握するEJB 3.1の新機能
第42回 次世代の携帯端末向けJava仕様"MIDP 3.0"はどうなるか その2
第41回 次世代の携帯端末向けJava仕様"MIDP 3.0"はどうなるか その1
第40回 リソースアダプタによる接続の仕組み
第39回 JCAを利用したシステム間接続
第38回 Java EEと外部システムの接続性を支えるJCAがバージョンアップ
第37回 Javaのモジュラリティ強化を担う"スーパーパッケージ"とは
第36回 JSR 308対応のコンパイラを試す
第35回 公開されたJSR 308のEarly Draftを検証する
第34回 スクリプト言語とJavaを結びつけるJSR 223
第33回 Java EE環境に統一されたコンポーネントモデルを提供するJSR 299 その2
第32回 Java EE環境に統一されたコンポーネントモデルを提供するJSR 299 その1
第31回 Javaの文法がそのまま使えるスクリプト言語"BeanShell"
第30回 Javaアプリケーションにオブジェクトのキャッシュ機構を提供するJCache API
第29回 Javaアプリケーションからのリソース管理を可能にするJSR 284
第28回 XMLデータソースへの問い合わせはJSR 225で
第27回 Portlet Specification 2.0をもっと手軽に利用する
第26回 次期Javaポートレット仕様となるJSR 286
第25回 JSFとポートレットをつなげるJSR 301
第24回 Webサービス向けのポートレット仕様「WSRP」
第23回 高い相互運用性を実現するポートレットAPI - JSR 168
第22回 Java EE環境でタスクのスケジューリングを可能にするJSR 236
第21回 Java EE環境でのスレッドプログラミングを可能にするJSR 237
第20回 音声認識/合成のためのAPI - Java Speech APIとJSR 113
第19回 JSR 291でJavaプラットフォームにダイナミックコンポーネントモデルを導入
第18回 JAX-RSで簡単RESTful - JSR 311
第17回 待望のServlet 3.0がJSRに登場 - JSR 315
第16回 アノテーションを使ってバグ退治 - JSR 305
第15回 アノテーションをさらに広い範囲で利用可能にするJSR 308
第14回 Webアプリケーション開発の要となるか - JSF 2.0がJSRに登場
第13回 Webサービス経由でのJMX Agentへの接続を可能にするJSR 262
第12回 Javaアプリケーションのモジュール化をサポートするJava Module System
第11回 "NIO.2"がやってきた - JSR 203: More New I/O APIs for the Java Platform
第10回 JSR 295: Beans Bindingの参照実装を試す
第9回 けっこう便利! 単位を扱うAPI -- JSR 275: Units Specification
第8回 アノテーションでバリデーション - JSR 303: Bean Validator
第7回 Swing開発の救世主となるか - Swing Application Framework
第6回 JavaBeansのプロパティを同期させるバインディングAPI
第5回 誰よりも早く"Java SE 7"を睨む
第4回 日時情報の取り扱いを改善する JSR 310: Date and Time API
第3回 古いAPIも進化している!? - JSR 919: JavaMail 1.4
第2回 JSR 1 リアルタイムJava仕様
第1回 JCPによって進められるJava関連技術の標準化

もっと見る

提供:マイナビ

会員登録はこちら

大学・大学院・短大・専門学生向けの就職情報サイト「マイナビ2010」「マイナビ2009」に今すぐ登録しよう!  大手企業からベンチャー企業までの約13,000社の企業情報を公開、エントリーが可能です。2010年卒予定の方は「マイナビ2010」に、2009年卒予定の方は「マイナビ2009」に登録してください。

毎日コミュニケーションズはプライバシーマークを取得しています。

関連キーワード


人気記事

一覧

イチオシ記事

新着記事