matsukaz's blog

Agile, node.js, ruby, AWS, cocos2d-xなどなどいろいろやってます

Java 7のクロージャ

Closures for the Java Programming Language (aka BGGA)Java 7で実装予定のクロージャが公開されています。ってなわけで軽く試してみました。

環境準備

まずはクロージャを利用したコードをコンパイル&実行するための環境作り。といっても簡単で

  1. Closures for the Java Programming Language (aka BGGA)で公開されているhttp://www.javac.info/closures.tar.gzを展開
  2. 展開後のディレクトリ/binをPATHに通す
    • %JAVA_HOME%/binより前に来るように注意する

だけです。

クロージャを使ってみる

クロージャ

{引数 => 戻り値}

という型になります。んで中身を定義するときは

{
  String hoge =>
  String message = "hello, " + hoge;  // 処理
  return message;                     // 戻り値
}

ってな感じ。実際のコードはこうかな。

import java.util.*;
 
public class Sample {
 
  // クロージャ内から定数が見れるか
  public static final String BAZ = "baz";

  public static void main(String[] args){
    
    String[] strs = {"hoge", "fuga"};
    
    // クロージャを持つリスト。クロージャは引数がString、戻り値がvoid
    List<{ String => void }> closures = new ArrayList<{ String => void }>();
    
    // str1はクロージャのスコープ外で定義された変数
    // クロージャ内から参照しているため、@Sharedを入れないとコンパイルで警告が出る
    @Shared String str1;
    
    // str2はクロージャ毎の変数
    for (String str2 : strs) {
      
      str1 = str2;
      
      // クロージャを定義
      closures.add({
        String param =>
        System.out.println(BAZ + ":" + str1 + ":" + str2 + ":" + param);
      });
    }
    
    for ({ String => void } closure : closures) {
      closure.invoke("foo");
    }
  }
}

こいつを実行すると

C:\temp\work>java Sample
baz:fuga:hoge:foo 
baz:fuga:fuga:foo

と表示されます。
ポイントは、for文で繰り返すたびに変数定義されるstr2は各クロージャ毎の変数になるけど、for文の外で定義されたstr1は全てのクロージャから参照される変数だってところ。なのでstr1を参照するとどのクロージャも同じ値を参照しています。うーん、どうにも慣れない。

正直クロージャは皆が分かるような仕様じゃないし、利用した方が良い場面も少なそう(GUI系のイベント登録とか?)なのであんまり使うことはないかなぁ、と。自前でライブラリとか作るときは便利かもしれないけど。