Java 言語は、
SUN の配布する次の Java 2 Platform, Standard Edition 1.5 (以下、J2SE 1.5) から
その言語仕様に大きな修正が加えられる予定だ。
その内容を SUN のエンジニア Dr. Joshua Bloch が
紹介するページが公開された
(ここ)。
J2SE 1.5 で Java 言語仕様に追加される予定の機能は大きく6点。
ただし、仕様は決定ではないので、まだ変更される可能性がある。
1. Generics
すでに予告されたように C++ の template のような generic type が 言語仕様に追加される。
従来の JDK のライブラリでは、 java.util.List や java.util.Map などのコンテナクラスは、 すべてのオブジェクトを基底クラス Object として取り扱ってきた。 つまり、 コンテナにはどんな種類のオブジェクトでも格納することが可能だった。
List words = new ArrayList(); words.add( word ); String title = ((String) words.get(i)).toUppercase();
しかし、 ユーザーは String クラスを収めるコンテナ、 自分の作成したクラス収めるコンテナのように、 特定の型に特化したコンテナを必要とすることの方が多い。 従来のコンテナクラスでは、 間違った型の要素を誤ってコンテナに挿入することを防ぐことができなかった。
Generic type を用いると 次のようにコンテナクラスを特化できる。
List<String> words = new ArrayList<String>(); words.add( word ); String title = words.get(i).toUppercase();
この機能を使うと、 特定クラス(この例では Stringクラス) に特化したコンテナが作成できる。
このコンテナへ要素を挿入・取り出す場合には コンパイラによる要素の型チェックが入る。 その結果、 コンテナクラスの意味が明確になり、 型チェックによって安全性が向上し、 実行時のエラーを減少させることができる。
Java の Generic type は C++ の template と違い、
特化したクラス毎の実体は生成しない。
Java のソースコードをコンパイルし終わると、
List<String> は従来の List コンテナに置換された
バイトコードとなって出力される。
また、
J2SE1.5 の generic type は、
primitive 型へ特化(List<int> など) はできないようだ。
2. Enhanced for Loop
Java 言語では、
コレクションや配列の内容を全て列挙するために
for 構文が利用される。
for (Iterator<Strin>; i = c.iterator(); i.hasNext(); ) {
String s = i.next();
// Body
}
このコレクションから要素を取り出すという動作をより明確にするために、
Perl や C# 言語は foreach 構文を持っている。
J2SE 1.5 から、
for に
foreach のような機能を実現する
構文が追加された。
上の Java プログラムを 新しい構文で書き直すと以下のようになる。
for (String s : c ) {
// Body
}
generic type のコンテナだけでなく、 従来のコレクションクラスや配列型も、 この新しい構文を使うことが可能だ。
配列の場合は、
int sum = 0;
for( int i=0 ; i<a.length ; i++ ){
int e = a[i];
sum += e;
}
上の表現を下のように書き改めることができる。
int sum = 0;
for( int e : a ){
sum += e;
}
また enum型の仕様が拡張されたのと合わせて、
以下のような表現も可能になった。
enum Day {Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };
for (Day d : Day.VALUES){
// Body ...
}
3. Autoboxing / unboxing
boxing と unboxing が使えるようになった。
ブラボー!!
従来の Java 言語では、
primitive 型の変数をオブジェクトとして扱いたい場合には、
ラッパークラスのインスタンスへ変換を行う必要があった。
例えば、int 型 のラッパークラスは java.lang.Integer クラスである。
int 型を Integer クラスに変換し、
そこから逆変換するためには以下のようなコードを
必要とした。
int i1 = ... ; Integer I1 = new Integer( i1 ); int i2 = I1.intValue();
これと等価な処理が
Integer I1 = (Integer) i1; int i2 = (int) I1;
と書けるようになった これは完全に C# の影響だと思われる。
4. Typesafe Enums
enum 型が大幅に拡張された。 かいつまんで紹介する。
- クラスのように定義enum は単なる整数定数の羅列というのに留まらず、クラスのように定義できる。
enum の要素は hashCode を持ち比較可能で、toString も使える(public enum Coin { penny(1), nickel(5), dime(10), quarter(25); Coin(int value) { this.value = value; } private final int value; public int value() { return value; } }(String) Coin.penny == "penny"とか)。
- VALUES、family()、valueOf()
各 enum 型は、以下のようなメソッド、フィールドが自動的に生成されるようになった。この機能は、拡張された for 構文で利用可能する際に便利で、以下のように書ける。public static List<this enum class> VALUES; public final List<this enum class> family(); public static <this enum class> valueOf(String name);
valueOf() を用いるとenum Day {Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday }; for (Day d : Day.VALUES){ // Body ... }Day.Sunday == Day.valueOf( "Sunday" )のような比較も可能も可能になる。
- Behavior を定義
以下のように enum のひとつづつに static なメソッドを割り当てることができ、eval メソッドを使うことで多態性のあるメソッド呼び出しが実現できるようだ。public abstract enum Operation { plus { double eval(double x, double y) { return x + y; } }, minus { double eval(double x, double y) { return x - y; } }; // Perform arithmetic operation represented by this constant abstract double eval(double x, double y); public static void main(String args[]) { double x = Double.parseDouble(args[0]); double y = Double.parseDouble(args[1]); for (Iterator<Operation> i = VALUES.iterator(); i.hasNext(); ) { Operation op = i.next(); System.out.println(x + " " + op + " " + y + " = " + op.eval(x, y)); } } } java Operation 2.0 4.0 2.0 plus 4.0 = 6.0 2.0 minus 4.0 = -2.0これ以外の機能も多数 追加されている。
5. Static Import
あるクラスの名前空間に、 他のクラスやインターフェイスの static なメソッドやフィールドを 取り込めるようにする static import 機能が追加された。
Java は C/C++ のようなマクロが使えないため、 定数の集合をインクルードした場合、 以下のようなテクニックを使うようになっていた。
public interface Physics {
public static final double AVOGADROS_NUMBER = 6.02214199e23;
public static final double BOLTZMANN_CONSTANT = 1.3806503e-23;
public static final double ELECTRON_MASS = 9.10938188e-31;
}
public class Guacamole implements Physics {
public static void main(String[] args) {
double moles = ...;
double molecules = AVOGADROS_NUMBER * moles;
...
}
}
この implements は概念的には、インターフェイスを継承したのではなく、 Guacamole クラスの名前空間の中に定数集合を取り込むためのものである。 interface の本来の概念からは外れていて好ましくない。
新たに定義された static import を使うと、 以下のように書けるようになる。
import static org.iso.Physics.*;
class Guacamole {
public static void main(String[] args) {
double molecules = AVOGADROS_NUMBER * moles;
...
}
}
また、Math クラスを static import すると、 Math.abs(x)、Math.sqrt(x) と書いていたコードが abs(x)、sqrt(x) と 書けるようになる。
6. Metadata
ドラフトが公開されていないため概念が掴めないが、 ツール類が Java のソースコードをうまく扱えるようにするための 機構のようだ。
例えば、metadata を埋め込まれた以下のようなソースがある場合、
import javax.xml.rpc.*;
public class CoffeeOrder {
@Remote public Coffee [] getPriceList() {
...
}
@Remote public String orderCoffee(String name, int quantity) {
...
}
}
これをツールが解釈して、 以下のようなコードを生成できるように することを狙ったている(らしい)。
public interface CoffeeOrderIF extends java.rmi.Remote {
public Coffee [] getPriceList()
throws java.rmi.RemoteException;
public String orderCoffee(String name, int quantity)
throws java.rmi.RemoteException;
}
public class CoffeeOrderImpl implements CoffeeOrderIF {
public Coffee [] getPriceList() {
...
}
public String orderCoffee(String name, int quantity) {
...
}
}