Java SEの次期バージョン(Java SE 7)での導入が検討されている「プロパティ」と、それに伴う言語仕様変更が全貌を現しつつある。java.net内のRemi Forax氏のブログによると、プロパティの仕様は現在ドラフト3を閲覧できる状態にあるという。本稿ではそのドキュメントを基に、プロパティが現時点でどのように検討されているのかを見ていきたい。

まず先に、現在のJava言語において「プロパティ」がどういう扱いなのかを復習しておきたい。

ご存じのとおりプロパティとは、クラスが持つ「状態」に対してアクセスするためのAPIだ。多くの場合、フィールドを実体に持つが、記述できるのはそれだけではない。

クラスの状態が変更された場合、副作用として何らかの処理を実行しなければならないこともある。そうしたクラス実装の詳細をカプセル化するための仕組みを、多くのプログラミング言語でプロパティと呼ぶが、Javaには現在のところプロパティが言語仕様として定義されていなかった。

代わりにJavaBean仕様という枠組みの中で、言語仕様外の取り決めとしてJavaにおける「プロパティ」の扱いが定められていた。それはset/getを接頭辞に持ち、それに続く単語の頭文字を大文字にした名前を持つメソッドというものであった(細かく言えば、boolean型の読み取りプロパティはisで始めることが許されたり、「getURL()」のように接頭辞の後に複数大文字が連続してもよかったり、といった取り決めがある)。これらは一般にアクセッサメソッドと呼ばれる。こうした規則に則ったAPIとしてjava.beansパッケージが標準APIに用意されており、そのAPIを用いれば、文字列とリフレクションを使って、それらのアクセッサメソッドに対し「プロパティ」としてアクセスできたのである。Java SE 7で進められている取り組みは、こうしたやり方を根本から見直そうとする動きである。

アクセッサメソッドというアプローチは、以下のような欠点を抱えていた。

  • 命名規約に準じた文字列操作と、リフレクションを用いるため、コンパイル時のチェックが働かない
  • アクセッサメソッドを記述するための、似たようなコードが大量に必要となる
  • 間違いを犯しやすい。具体的には、setterメソッドの名称だけを変えてgetterを変え忘れる、誤ってアクセッサをオーバーロードしてしまう、など

こうした欠点を補うべく、Java7で導入されるプロパティは以下のようなものを目指している。

  • きわめて簡潔な文法でプロパティを定義できるようにすることで、コード記述量を減らし、ケアレスミスも防ぐ
  • プロパティに対して動的にアクセスするための文法を追加し、可能な限りコンパイル時にチェックを行う

では、具体的に見ていこう。

簡潔になったプロパティの定義方法

現在のドラフトで検討されているプロパティの定義方法は以下のようなものである。

  • ローカルキーワード「property」を導入し、「public property String s;」のように宣言できる
  • 読み取り専用、書き込み専用プロパティの作成方法は、ローカルキーワードget/setをプロパティ宣言の後に記述することで行う。例えば、「public property String s get;」とすれば読み取り専用になる
  • プロパティの変更に応じて処理を実行させることができる。そうしたプロパティ(バウンドプロパティ)は、宣言の後にローカルキーワードboundを記述し、propertyChanged()メソッドにプロパティ変更時の処理を記述する(具体例は後述)
  • プロパティアクセス時の処理を自分で行いたい場合は、ユーザ定義プロパティとして、プロパティ本文を開発者自ら記述することが可能

文章中に出てきたローカルキーワードは、これまでのJavaには存在しなかった文法要素だ。これはJava言語のキーワード(class、staticなど)ではなく、普段は識別子として使用できるが、文脈によっては特別な意味を持つというキーワードだ。こうした文法要素の導入により、J2SE 1.4のassert、Java SE 5のenumなどで生じたような、キーワードの追加によって新しいコンパイラでソースがコンパイルできないといった混乱を回避するとみられる。

上のルールを具体的にコードで表すと以下のようになる。

リスト1:プロパティの様々な宣言方法

public class MyBean {
    public property String name1; // 読み書き可能なプロパティ
    public property String name2 get; // 読み取り専用
    public property String name3 set; // 書き込み専用
    public property String name4 bound; // バウンドプロパティ
    public property String name5 get set; // 文法エラー

    public property String name6 get { return "hello"; }; // 読み取り専用
    public property String name7 set(String name) { }; // 書き込み専用

    private boolean isReal;

    // ユーザ定義プロパティ。以下の場合は読み書き可能
    public property String real
        get { 
            return String.valueOf(isReal); 
        }
        set(String real) {
            isReal= String.decode(real); 
        };
 }

現在のところ、propertyキーワードで宣言されたプロパティは、その実体となるフィールドと、そのフィールドへのアクセッサメソッドをコンパイラが勝手に生成するという実装を想定しているようだ。そのため、アクセス修飾子、synchronized、もしくはvolatileやstaticといったキーワードをプロパティに付けると、あるものは生成されたフィールドに、あるものはメソッドにというように、適切な箇所にそのキーワードが付与されたのと同じ効果が得られる。