Collections
Commons Collectionsは、これだけを単独の記事として取り上げてもよいほど大きなトピックです。本稿ではAPIについて概説するにとどめ、最も一般的な実例を示します。
JDKにJava Collections Frameworkがあるのに、なぜCommons Collectionsが必要なのかと疑問を持つ人もいるかもしれません。Collectionsは、Java Collections Frameworkのクラスとインターフェイスを拡張し、機能強化するものです。実のところ、私はこれをJDKの一部にすべきだとさえ思っています。
私が特に好んで使用している機能をいくつか挙げておきます。
- バッグインターフェイス
- 固定サイズ、デュアル、およびLRUのマップ
- オブジェクト配列およびマップのイテレータ
- マップのMultiKey
- APIを使いやすくする多数のユーティリティクラス
- 大部分のクラスの動作をカスタマイズできるデコレータ
Collectionsのクラスは次のようなパッケージに編成されています。
- org.apache.commons.collections
- org.apache.commons.collections.bag
- org.apache.commons.collections.bidimap
- org.apache.commons.collections.buffer
- org.apache.commons.collections.collection
- org.apache.commons.collections.comparators
- org.apache.commons.collections.functors
- org.apache.commons.collections.iterators
- org.apache.commons.collections.keyvalue
- org.apache.commons.collections.list
- org.apache.commons.collections.map
- org.apache.commons.collections.set
org.apache.commons.collections
「org.apache.commons.collections」パッケージには、他のパッケージで実装されているインターフェイスと、コレクションクラスまたはコレクションクラスのデコレートバージョンをインスタンス化するためのファクトリとして機能するユーティリティクラスが含まれています。ArrayStack、BeanMap、ExtendedProperties、FastArrayList、FastHashMap、FastTreeMapといった注目すべきクラスが含まれています。これらのクラスの詳細情報はjavadocに網羅されていますが、表1で各クラスの実際の用法を簡単に紹介しておきます。
| コレクションクラス | 実際の用法 |
ArrayStack | ArrayStackはシングルスレッド環境で使用するためにArrayListをスタック実装にしたものです。たとえば、特定のメソッドの中でだけ何かの処理にスタックを使用したいという場合は、この実装を使用した方がJDK-1.4.2のVectorを使ったスタック実装よりも有利です。 |
BeanMap | Swing GUIウィジェットのJButtonと同様、このクラスを使用すると、マップさえもJava Beanとして扱うことができます。アプリケーションのデータソースや一連の設定プロパティを表現するGUIをデザインする際に、マップを画面上でドラッグアンドドロップすることができます。 |
ExtendedProperties | このパッケージで私が最も気に入っているクラスです。設定プロパティをロードするためのloadメソッドを持つjava.util.Propertiesに似ていますが、こちらの実装には次のような利点があります。・同じプロパティキーに複数の値を持たせることができます。 ・値を異なる行に分割することができます。 ・非文字列値を取得するための便利なヘルパーメソッドがあります。 たとえば、 getFloatメソッドはfloat型のプロパティを取得します。そのため、設定プロパティ値を解析するためにラッパーメソッドを書く必要はありません。 |
FastArrayList、FastHashMap、FastTreeMap | 大部分の操作が読み取り専用ならば、これらのクラスをマルチスレッド環境で使用できます。これらのクラスは、それぞれArrayList、HashMap、TreeMapをベースにしています。 |
org.apache.commons.collections.bag
org.apache.commons.collections.bagクラスは、オブジェクトの複数のコピーをListに追加するという要件を備えたアプリケーションでとても役に立ちます。こうした状況では、通常は、オブジェクトをArrayListに追加し、特定の型の追加オブジェクトの数を判定する際には毎回反復処理を行うという方法が使われています。この要件に該当する好例はオンラインショッピングカートです。このアプローチの欠点は、メモリと速度の面でパフォーマンスが劣ることです。
この要件に対処するには、オブジェクトのコピーを1つだけ保持し、同じ型のエントリが新たに追加されるたびにカウントを増やしていくというやり方が好ましいでしょう。それにはCommons CollectionsのHashBagクラスとTreeBagクラスが適しています(それぞれHashMapとTreeMapをベースにしています)。
ソースコードの「in.co.narayanan.commons.collections.bag」パッケージを見ると、バッグの実際の用法がわかります。このサンプルでは、さまざまなオペレーティングシステムのソフトウェアライセンスの注文を処理し、バッグ内の注文された製品を表現しています。
これらのクラスでは、もっと具体的なバージョンやデコレータが利用できます。詳細についてはjavadocを参照してください。
org.apache.commons.collections.bidimap
たいていのJava開発者は、キー/値のキーを取り出したい場合には、2つのHashMapを用意し、1つ目のHashMapの値を2つ目のHashMapにキーとして渡す、という方法を使用してきました。通常、名前と値を平等に扱いたければ、このテクニックを使用する必要があります。このケースでは値さえもキーになり得ます。
org.apache.commons.collections.bidimapは、PeopleSoftとSiebelのコマンド処理エンジンを統合するプロトタイプアダプタです(ただし、双方に同等のコマンドが存在することが前提となります)。このアダプタの関連クラスは「in.co.narayanan.commons.collections.bidimap」パッケージに含まれています。まず、サンプル内のクラスSiebelPeopleSoftConnectorのコードをひととおり見てみてください。このクラスはアダプタとして働き、コマンドマッピングをBidiMap内に保持します。Siebelコマンドを処理する要求が到着すると、BidiMapから対応するPeopleSoftコマンドが取得され、PeopleSoftコマンドエンジンに渡されます。PeopleSoftコマンドでは逆の処理が行われます。このサンプルに含まれているのはアプリケーションのスケルトンだけです。
請負で設計をする場合は、このクラスの修正不能バージョン(開発者が内容を変更できないもの)を使用すると便利です。これにより、開発者が内容を処理しているときに誤りを犯す危険性を大幅に減らすことができます。
org.apache.commons.collections.buffer
コレクションから特定の順序でオブジェクトを取り除きたい場合は、バッファインターフェイスの実装を利用することができます。注目すべきクラスとして、CircularFifoBuffer、PriorityBuffer、BoundedFifoBuffer、BlockingBufferなどを挙げることができます。いずれにもデコレートバージョンがあります。
パッケージ「in.co.narayanan.commons.collections.buffer」にバッファサンプルがあります。これはCircularFifoBufferクラスの例を示しています。このクラスは移動ウィンドウと考えることができます。コレクションのサイズは固定しており、満杯になるとオブジェクトが先入れ先出し(FIFO)方式で削除されます。
このアプリケーションの目的は、リモートサーバーにパフォーマンスデータを報告することです。パフォーマンスデータは監視に使用されるだけなので、データが失われてもそれほど問題にはなりません。パフォーマンスデータを報告するクライアントアプリケーションは、ReportPerformanceDataクラスをインスタンス化し、reportPerformanceメソッドを呼び出す必要があります。パフォーマンスデータは循環バッファに追加されます。
ReportTaskクラスはパフォーマンスデータオブジェクトを削除し、それをパフォーマンスサーバーに送ります。報告タスクを非同期に開始するためにJava 1.5の並行処理ユーティリティクラスThreadPoolExecutorが使用されるので、バッファ内に報告すべきデータがあればデータが報告されます。
org.apache.commons.collections.collection
「org.apache.commons.collections.collection」パッケージにはデコレータクラスが含まれています。これらのクラスはjava.util.Collectionインターフェイスを直接実装しています。そのため、Collectionインターフェイスを実装しているクラスならどのクラスでも、これらのデコレータを利用することができます。PredicatedCollection、CompositeCollection、SynchronizedCollection、TransformedCollection、TypedCollection、UnmodifiableCollectionなどがよく使われるクラスです。表2に、これらのデコレータをどのような場合に使用するかを示します。
| デコレータクラス | 使用する状況 |
PredicatedCollection | コレクションへのオブジェクトの追加を"amount >= $15000"などの条件で制限したいとき。このクラスをインスタンス化するには、条件を別オブジェクトとして定義します。これはプレディケイトとして呼び出され、decorateファクトリメソッドに引数として渡されます。 |
CompositeCollection | コレクションのコレクションを作成し、オブジェクトの追加または削除を統一的な方法で行いたいとき。 |
SynchronizedCollection | 既存のコレクションをスレッドセーフにしたいとき。 |
TransformedCollection | コレクションへの追加時に常にオブジェクトの形式を変換したいとき(たとえばStringからIntegerに変換するなど)。 |
TypedCollection | コレクションに追加するオブジェクトの型を制限したいとき。これはJava 1.5のgenericsに似ています。 |
UnmodifiableCollection | 既存のコレクション参照への修正を制限したいとき。 |
org.apache.commons.collections.comparators
このパッケージにはさまざまな再利用可能クラスが含まれており、コレクション内でオブジェクトをソートするときに役立ちます。特に注目したいのがNullComparatorクラスとFixedOrderComparatorクラスです(表3を参照)。
| 再利用可能なクラス | 機能 |
NullComparator | 配列またはリストの中でエントリをソートする際にnullエントリを最後部に移動します。 |
FixedOrderComparator | コレクション内での順序をあらかじめ定義されたリストに戻します。 |
org.apache.commons.collections.functors
「org.apache.commons.collections.functors」パッケージについては、後のセクションで詳しく説明します。
org.apache.commons.collections.iterators
「org.apache.commons.collections.iterators」パッケージ内の多くのクラスはjava.util.Iteratorインターフェイスを実装しています。MapIterator、ArrayIterator、CollatingIterator、LoopingIterator、IteratorUtilsなどが最も役に立つクラスです。このパッケージ内のクラスを利用するには、IteratorUtilsクラス内のメソッドをよく調べる必要があるでしょう。
org.apache.commons.collections.keyvalue
「org.apache.commons.collections.keyvalue」パッケージ内のMultiKeyクラスは非常に有用です。アプリケーション内でドメインオブジェクトを作成し、それを複合主キーと対にしてマップに格納したい場合は、対象レコードの主キーを構成する値を渡してMultiKeyのインスタンスを作成します。その後、このインスタンスをドメインオブジェクトを格納するためのマップに渡します。
このパッケージのその他の一般的な用法として、ロケール固有のエントリをマップに格納するという例が挙げられます。この場合は、実際のキーとロケール名からキーが構成されます。
org.apache.commons.collections.list
「org.apache.commons.collections.list」パッケージ内の注目すべきクラスは、TreeList、FixedSizeList、NodeCachingLinkedList、CursorableLinkedList、TransformedList、PredicatedListです。これらのクラスのことは、javadocを見ればすぐに分かります。
org.apache.commons.collections.map
「org.apache.commons.collections.map」パッケージ内の注目すべきクラスは、CaseInsensitiveMap、CompositeMap、FixedSizeMap、Flat3Map、LazyMap、LinkedMap、LRUMap、MultiKeyMap、PredicatedMap、SingletonMap、StaticBucketMapです。これらのクラスのことは、javadocを見ればすぐにわかります。
org.apache.commons.collections.set
「org.apache.commons.collections.set」パッケージ内の注目すべきクラスは、CompositeSet、ListOrderedSet、MapBackedSet、PredicatedSet、TransformedSet、TypedSet、UnmodifiableSetです。これらのクラスのことは、javadocを見ればすぐにわかります。
