J2SE 5.0 のコレクションクラス

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 となります。

J2SE 1.4 までの規則

次のメソッドは、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>

Generics

早速、警告で指定されている部分を 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/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);
	}
}

Enhanced For Loop

最後に、イテレーションの部分を拡張 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>


Copyright © 2005 SUGAI, Manabu. All Rights Reserved.
SEO [PR] !uO z[y[WJ Cu