Revised: May/10th/2008; Since: Aug./07th/2005
J2SE 5.0 では言語仕様に大きな変更があります。コレクションクラスは、その影響を大きく受けるAPIです。本文中でも随時解説してきましたが、ここで、次の三つの追加仕様に注目して、J2SE 5.0での記述方法を見てみましょう。
J2SE は 1.5 (通称 Tiger)の開発中にバージョニング規則が変わり、 5.0 と呼称されるようになりました。また、 J2SE という呼称は 5.0 で最後であり、6.0 (通称 Mustang)では Java SE と呼称されます。また、J2EE も、1.5からJava EE 5となります。
次のメソッドは、Collection インタフェースに従ってコレクションを操作するメソッドです。何れのメソッドも、引数として Collection 型のオブジェクト参照を受け取ります。使っているメソッドは、インタフェース Collection で宣言されたものだけなので、これを実装するクラス型オブジェクトは何でも処理可能です。
// 要素の追加
public void addElapsedTime(Collection container, int MAX) {
long start = System.currentTimeMillis();
System.out.println(container.getClass().getName());
for (int i = 0; i < MAX; i++) {
// コレクションへの要素の追加
container.add(new Integer(i));
long end = System.currentTimeMillis();
if (i % 100000 == 0) {
System.out.print(end - start + ", ");
} else if (i == MAX - 1) {
System.out.println(end - start);
}
}
}
// イタレーションによる要素の取り出し
public void getElapsedTime(Collection container) {
long start = System.currentTimeMillis();
Integer obj = new Integer(0);
int sum = 0;
// 要素についての繰り返し(イタレータの利用)
for (Iterator itr = container.iterator(); itr.hasNext(); ) {
// Object型からInteger型へキャスト
obj = (Integer)itr.next();
// Integer型からプリミティブ型へ変換
sum += obj.intValue();
}
long end = System.currentTimeMillis();
System.out.println(end - start);
}
というわけで、これらのメソッドを使うメソッドとして次のものを用意します。
import java.util.Collection;
import java.util.Iterator;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.HashSet;
import java.util.TreeSet;
import java.util.LinkedHashSet;
import java.util.PriorityQueue;
public class CollectionDemo {
// 要素の追加
public void addElapsedTime(Collection container, int MAX) {
...
}
// イタレーションによる要素の取り出し
public void getElapsedTime(Collection container) {
...
}
// テスト用コントロールメソッド
// 引数はコレクションの要素の個数
// 例# java CollectionDemo 100000
public static void main(String[] args) {
int MAX = Integer.parseInt(args[0]);
CollectionDemo container = new CollectionDemo();
// ArrayList 型オブジェクト
Collection obj = new ArrayList();
container.addElapsedTime(obj, MAX);
container.getElapsedTime(obj);
// LinkedList 型オブジェクト
obj = new LinkedList();
container.addElapsedTime(obj, MAX);
container.getElapsedTime(obj);
// HashSet 型オブジェクト
obj = new HashSet();
container.addElapsedTime(obj, MAX);
container.getElapsedTime(obj);
// TreeSet 型オブジェクト
obj = new TreeSet();
container.addElapsedTime(obj, MAX);
container.getElapsedTime(obj);
// LinkedHashSet 型オブジェクト
obj = new LinkedHashSet();
container.addElapsedTime(obj, MAX);
container.getElapsedTime(obj);
// PriorityQueue 型オブジェクト
obj = new PriorityQueue();
container.addElapsedTime(obj, MAX);
container.getElapsedTime(obj);
}
}
これを、JDK 5.0 でコンペア/実行結果すると、次のようになります。
C:\java>javac CollectionDemo.java
注: CollectionDemo.java の操作は、未チェックまたは安全ではありません。
注: 詳細については、-Xlint:unchecked オプションを指定して再コンパイルしてくださ
い。
C:\java>javac -Xlint:unchecked CollectionDemo.java
CollectionDemo.java:10: 警告: [unchecked] raw 型 java.util.Collection のメンバと
しての add(E) への無検査呼び出しです。
container.add(new Integer(i));
^
警告 1 個
C:\java>java CollectionDemo 1000000
java.util.ArrayList
0, 31, 78, 125, 156, 219, 234, 328, 359, 375, 391
62
java.util.LinkedList
0, 62, 94, 125, 156, 187, 359, 375, 422, 453, 657
47
java.util.HashSet
0, 109, 172, 218, 281, 437, 469, 516, 609, 672, 719
62
java.util.TreeSet
0, 94, 204, 376, 501, 610, 720, 829, 923, 1048, 1158
78
java.util.LinkedHashSet
0, 94, 172, 297, 375, 438, 516, 563, 657, 735, 1079
63
java.util.PriorityQueue
0, 31, 93, 109, 140, 187, 218, 234, 250, 297, 312
32
C:\java>
コンパイル時に出されている警告が、J2SE 5.0 での追加仕様の部分です。コレクションフレームワークの API が変更になっているのに、従来の 1.4 の記述方法のままなので、警告が出されているわけです。承知の上であれば、コンパイル時オプションに、1.4 準拠である旨を明示すれば、このエラーは出されません。
C:\java>javac -source 1.4 -target 1.4 CollectionDemo.java C:\java>
早速、警告で指定されている部分を 5.0 準拠に変更してみましょう。
警告で指定されているのは、ソースコードの 10 行目、「container.add(new Integer(i));」です。5.0 に準拠すると、次のように修正すべきです。メソッド引数で受け取るコレクションに、要素は Integer だけであることをパラメタとして指定しておくわけです。
こうすることで、Integer 以外のものを add しようとすると、例外が発生します。
また、要素を取り出したとき、従来は Object 型で取り出されていたので、明示的にダウンキャストが必要でしたが、型パラメタで指定してあるので、キャスト不要で目的の型として受け取ることが出来ます。
// 要素の追加
public void addElapsedTime(Collection<Integer> container, int MAX) {
long start = System.currentTimeMillis();
System.out.println(container.getClass().getName());
for (int i = 0; i < MAX; i++) {
// コレクションへの要素の追加
container.add(new Integer(i));
long end = System.currentTimeMillis();
if (i % 100000 == 0) {
System.out.print(end - start + ", ");
} else if (i == MAX - 1) {
System.out.println(end - start);
}
}
}
// イタレーションによる要素の取り出し public void getElapsedTime(Collection<Integer> container) { long start = System.currentTimeMillis(); Integer obj = new Integer(0); int sum = 0; // 要素についての繰り返し(イタレータの利用) for (Iterator<Integer> itr = container.iterator(); itr.hasNext(); ) { // Integer型へキャスト不要 obj = itr.next(); // Integer型からプリミティブ型へ変換 sum += obj.intValue(); } long end = System.currentTimeMillis(); System.out.println(end - start); }
D:\java>javac CollectionDemo2.java D:\java>java CollectionDemo2 1000000 java.util.ArrayList 0, 31, 78, 125, 156, 219, 235, 328, 360, 375, 391 78 java.util.LinkedList 0, 63, 94, 141, 172, 203, 391, 422, 454, 485, 688 47 java.util.HashSet 0, 110, 172, 219, 282, 438, 485, 532, 610, 673, 719 63 java.util.TreeSet 0, 110, 203, 360, 485, 594, 704, 813, 923, 1032, 1142 78 java.util.LinkedHashSet 0, 78, 156, 297, 375, 438, 516, 579, 704, 782, 1110 63 java.util.PriorityQueue 0, 47, 109, 125, 156, 187, 219, 234, 266, 297, 313 46 D:\java>
続いて、Autoboxing/Unboxing について見てみましょう。Autoboxing とは、int型などのプリミティブ型の値を、Integer型などのラッパークラス型へ自動変換することです。Auto-Unboxing はその逆に、ラッパークラス型からプリミティブ型への自動変換です。要するに、次のことが出来るわけです。
String str = "100"; Integer intObj = Integer.valueOf(str); int x = intObj + 10; // Unboxing Integer intObj2 = x; // Autoboxing
ただし、 Autoboxing/Unboxing は、ラッパーとプリミティブ型間の変換なので、整数拡張などは施されません。intと自動ボクシング変換可能なのはIntegerのみです。
Autoboxing/Unboxing を用いてコードを書き換えると、次のようになります。
import java.util.Collection;
import java.util.Iterator;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.HashSet;
import java.util.TreeSet;
import java.util.LinkedHashSet;
import java.util.PriorityQueue;
public class CollectionDemo3 {
// 要素の追加
public void addElapsedTime(Collection<Integer> container, int MAX) {
long start = System.currentTimeMillis();
System.out.println(container.getClass().getName());
for (int i = 0; i < MAX; i++) {
// コレクションへの要素の追加
// Generics で指定してあるので、
// Integer以外のものを追加しようとすると例外発生
// Autoboxing
container.add(i);
long end = System.currentTimeMillis();
if (i % 100000 == 0) {
System.out.print(end - start + ", ");
} else if (i == MAX - 1) {
System.out.println(end - start);
}
}
}
// イタレーションによる要素の取り出し
public void getElapsedTime(Collection<Integer> container) {
long start = System.currentTimeMillis();
// Auto-Unboxingのため不要
// Integer obj = new Integer(0);
int sum = 0;
// 要素についての繰り返し(イタレータの利用)
for (Iterator<Integer> itr = container.iterator(); itr.hasNext(); ) {
// メソッド引数に Generics で指定してあるので
// Object型からInteger型へのダウンキャスト不要
// obj = (Integer)itr.next();
// Auto-Unboxing
// Integer型からプリミティブ型へ変換
// sum += obj.intValue();
sum += itr.next();
}
long end = System.currentTimeMillis();
System.out.println(end - start);
}
// テスト用コントロールメソッド
// 引数はコレクションの要素の個数
// 例# java CollectionDemo 100000
public static void main(String[] args) {
int MAX = Integer.parseInt(args[0]);
CollectionDemo container = new CollectionDemo();
// ArrayList 型オブジェクト
Collection obj = new ArrayList();
container.addElapsedTime(obj, MAX);
container.getElapsedTime(obj);
// LinkedList 型オブジェクト
obj = new LinkedList();
container.addElapsedTime(obj, MAX);
container.getElapsedTime(obj);
// HashSet 型オブジェクト
obj = new HashSet();
container.addElapsedTime(obj, MAX);
container.getElapsedTime(obj);
// TreeSet 型オブジェクト
obj = new TreeSet();
container.addElapsedTime(obj, MAX);
container.getElapsedTime(obj);
// LinkedHashSet 型オブジェクト
obj = new LinkedHashSet();
container.addElapsedTime(obj, MAX);
container.getElapsedTime(obj);
// PriorityQueue 型オブジェクト
obj = new PriorityQueue();
container.addElapsedTime(obj, MAX);
container.getElapsedTime(obj);
}
}
最後に、イテレーションの部分を拡張 For 文に書き換えてみます。
// イタレーションによる要素の取り出し
public void getElapsedTime(Collection<Integer> container) {
long start = System.currentTimeMillis();
int sum = 0;
// 要素についての繰り返し(拡張 For 文の利用)
// Auto-UnboxingによりInteger型は顕には記述しない
for (int i: container) {
sum += i;
}
long end = System.currentTimeMillis();
System.out.println(end - start);
}
D:\java>javac CollectionDemo4.java D:\java>java CollectionDemo4 1000000 java.util.ArrayList 0, 31, 78, 125, 156, 218, 250, 328, 359, 375, 406 63 java.util.LinkedList 0, 62, 94, 125, 156, 187, 359, 391, 438, 453, 672 47 java.util.HashSet 0, 110, 172, 219, 282, 438, 485, 532, 610, 673, 719 63 java.util.TreeSet 0, 94, 203, 360, 485, 594, 719, 829, 938, 1048, 1157 78 java.util.LinkedHashSet 0, 79, 157, 298, 360, 423, 501, 563, 642, 720, 1064 62 java.util.PriorityQueue 0, 32, 94, 110, 141, 172, 204, 219, 251, 282, 298 31 D:\java>