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 SE と同じく Java EE 5.0 となります。
次のメソッドは、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.*; 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, 78, 172, 234, 266, 391, 422, 531, 547, 578, 609 47 java.util.LinkedList 0, 63, 110, 157, 188, 235, 407, 485, 532, 578, 813 47 java.util.HashSet 0, 172, 312, 406, 750, 859, 906, 1000, 1187, 1343, 1437 156 java.util.TreeSet 0, 157, 375, 500, 641, 766, 907, 1032, 1204, 1329, 1469 78 java.util.LinkedHashSet 0, 156, 281, 625, 1109, 1234, 1328, 1437, 1750, 2625, 2718 250 java.util.PriorityQueue 0, 47, 78, 109, 125, 141, 281, 297, 344, 359, 406 31 C:\java>
コンパイル時に出されている警告が、J2SE 5.0 での追加仕様の部分です。コレクションフレームワークの API が変更になっているのに、従来の 1.4 の記述方法のままなので、警告が出されているわけです。承知の上であれば、コンパイル時オプションに、1.4 準拠である旨を明示すれば、このエラーは出されません。
C:\java>javac -source 1.4 -target 1.4 CollectionDemo.jav 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);
}
}
}
C:\java>javac -Xlint:unchecked CollectionDemo2.java C:\java>java CollectionDemo2 1000000 java.util.ArrayList 0, 78, 172, 250, 266, 391, 422, 516, 547, 578, 609 47 java.util.LinkedList 0, 78, 110, 157, 203, 250, 407, 500, 532, 578, 813 47 java.util.HashSet 0, 156, 297, 390, 734, 859, 906, 1000, 1187, 1328, 1422 171 java.util.TreeSet 0, 157, 375, 500, 625, 766, 891, 1032, 1188, 1329, 1469 63 java.util.LinkedHashSet 0, 141, 282, 610, 1094, 1219, 1313, 1407, 1735, 2578, 2688 203 java.util.PriorityQueue 0, 78, 141, 219, 234, 250, 297, 312, 359, 375, 391 31 C:\java>
続いて、Autoboxing/Unboxing について見てみましょう。Autoboxing とは、int 型などのプリミティブ型の値を、Integer型などのラッパークラス型へ自動変換することです。Auto-Unboxing はその逆に、ラッパークラス型からプリミティブ型への自動変換です。要するに、次のことが出来るわけです。
String str = "100"; Integer intObj = Integer.parseInt(str); int x = intObj + 10; // Unboxing Integer intObj2 = x; // Autoboxing
ただし、 Autoboxing/Unboxing は、ラッパーとプリミティブ型間の変換なので、整数拡張などは施されません。int と自動変換可能なのは Integer のみです。
Autoboxing/Unboxing を用いてコードを書き換えると、次のようになります。
import java.util.*; public class CollectionDemo2 { // 要素の追加 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 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);
}
C:\java>javac CollectionDemo3.java C:\java>javac -Xlint:unchecked CollectionDemo3.java C:\java>java CollectionDemo3 1000000 java.util.ArrayList 0, 78, 172, 235, 266, 391, 422, 532, 563, 578, 610 47 java.util.LinkedList 15, 78, 125, 156, 187, 234, 406, 484, 515, 578, 812 47 java.util.HashSet 0, 156, 312, 406, 750, 875, 922, 1016, 1187, 1344, 1437 157 java.util.TreeSet 0, 156, 390, 515, 656, 781, 922, 1047, 1218, 1359, 1500 62 java.util.LinkedHashSet 16, 172, 297, 641, 1125, 1235, 1344, 1438, 1766, 2610, 2719 234 java.util.PriorityQueue 0, 78, 125, 203, 219, 235, 282, 297, 360, 360, 375 47 C:\java>
SEO | [PR] !uO z[y[WJ Cu | ||