この記事は、日経ソフトウエア2012年1月号に掲載されたものです。クロージャの記法は、2013年にリリースするJava SE 8で正式に決まるため執筆時点の記法とは異なることが予想されます。ただ、クロージャの考え方自体は変わらずに参考になる点が多いため転載します。

第4回では、一足先にJava SE 8で実装が予定されている機能を学んでいきます。Java以外の言語で既に導入されている機能なので、ここで学んだことはJava SE 8に取り入れられなくても他の言語を利用する際に役立つはずです。

 Java SE 8で導入が予定されている機能のうち「クロージャ」と「モジュール機構」について解説します。特にクロージャは、理解するのがやや難しいため、基本的な概念から説明していきます*1。クロージャの概念はJavaだけではなく、他のプログラミング言語でも利用できる知識です。例えJavaで利用できなくても、プログラミング言語全般の知識を深めるのに役立つでしょう。

マルチコア化で注目されたクロージャ

 クロージャは、Java SE 7に導入されるのではないかと何度も話題になり、大きな注目を集めている機能です。しかし、どのように導入するのかで決着が付かず、結局Java SE 8まで持ち越されました。クロージャ自体は、古くからよく知られているプログラミング言語の考え方です。Scalaなどの比較的新しい言語などでも使用できます。

 Javaがクロージャを導入しようとした背景には、CPUのマルチコア化が深く関与しています。Javaは以前からThreadクラスやConcurrency Utilitiesを導入して、マルチスレッドやマルチタスクでの実行をサポートしてきました。しかし、粒度の大きいタスクしか実行できないために、ヒープ領域の使用量が増大してパフォーマンスが上がらないという問題が発生していたのです(図1)。

図1●タスクの粒度を細分化したイメージ。実際にはもう少し複雑な処理になります
図1●タスクの粒度を細分化したイメージ。実際にはもう少し複雑な処理になります
[画像のクリックで拡大表示]

 そこで、より粒度の小さいタスクで実行できるように導入されたのが、第3回で学んだFork/Joinフレームワークです。ですが、これまでのJavaではタスクをパラレルに処理させるために、多くのインタフェースが必要になってしまいます。この問題を解決するため、クロージャをタスクとして扱う方法が考案されました。クロージャを使うとパラレル処理を実装する際に、短いプログラム記法で済むことから導入が予定されています。

 まずは、クロージャの説明をした後に、クロージャがどのようにJavaに導入されそうなのかを見ていきましょう。

関数オブジェクトを作成するクロージャ

 クロージャとは、簡単に言ってしまえば、「関数オブジェクトを作る機能」といえます。この説明だけでは「関数オブジェクトは何?」という疑問が生じますね。一つずつ疑問を解決していきましょう。

リスト1●Humanクラスを定義してインスタンス化するプログラム
リスト1●Humanクラスを定義してインスタンス化するプログラム

 関数オブジェクトを理解するには、そもそも「値」とは何か、を知っておく必要があります。プログラミング言語で扱える値として思い付くものには、数値や文字列などがあります。また、オブジェクト指向言語であれば、数値や文字などを組み合わせて作ったオブジェクトも値として扱えるでしょう。ここで、リスト1のようなHumanクラスを考えてみましょう。この場合、(1)のnewでインスタンス化したものは値になります。

 そして「hito」がオブジェクトの値を表す変数になっています。このように、値として扱えるものを、少し専門的な言葉で「第一級オブジェクト(First Class Object)」と呼びます*2。第一級オブジェクトは、変数に格納したり、関数の引数に渡したりできるわけです。第一級オブジェクト以外には、Javaにおけるメソッドなどが挙げられるでしょう。言ってしまえば、メソッドを値として扱えるようにする機能がクロージャになります。