オブジェクトの集まりを効率よく扱いたい!
コレクションとは、オブジェクト(データ)の集まりをあれこれと操作することが出来るクラスの集まりです。
コレクションで提供されているクラスにはリスト、セット、ツリーハッシュテーブルなどが存在し、自分のやりたいことにあわせたクラスを使用します。このコレクションに所属するクラスは、インタフェースと実装が明確に分けられており、コレクションを使うためにはインタフェースが提供するメソッドに沿うことにことになります。これにより、同じインターフェースを経由することで異なるクラスを同じロジックで使用することが出来ます。
このように、ある目的を達成するための枠組みをフレームワークと呼びます。コレクションはオブジェクトの集まりを体系的かつ効率的に扱うためのフレームワーク(枠組み)ということで、JavaCoiiectionsFramework(JCF)
と呼ばれています。
先ほど説明したように、コレクタはインターフェースが提供するメソッドを使用することから、インターフェースの種類と特徴を理解することが、コレクションを理解することに近道になります。コレクションが提供するクラスは決して万能なものではありません。それぞれの要件に応じたクラスを選択することが、コレクションクラスを使いこなす重要なポイントになります。
ここで少々、集合体の構造とデータ(コレクションに格納するデータのことを要素と呼ぶ場合があります)取り出し(データアクセス)について簡単に触れておきましょう。一般的にコンピュータで扱うデータの集合体に対するアクセス方法は「先入先出し」、「後入れ先出し」、「任意取り出し」の3つに分類することが出来ます。
これは、コンピュータ用語で 「Queue (キュー)」と呼ばれるもので、集合体に先に入れたものが取り出し時に先に取り出されます。早い話が、データを集合体に格納した順番でデータの取出しが行えます。コレクションでこの機能を実現する代表的なクラスが「ArrayList」です。
これは、コンピュータ用語で 「Stack (スタック)」と呼ばれるもので、集合体に後から入れたものが取り出し時に先に取り出されます。早い話が、データを集合体に格納した順番とは逆の順番でデータの取出しが行えます。コレクションでこの機能を実現する代表的なクラスが「Stack」です。
これは、コンピュータ用語で 「Map (マップ)」と呼ばれるもので、集合体に入れたものに印をつけておき、この印を頼りに取り出します。早い話が、好きなものを取り出すことが出来ます。コレクションでこの機能を実現する代表的なクラスが「HashMap」です。
コレクションが提供するインターフェースでよく使用するのは5種類です。これらは、集合体に対する「データ順序」、「データの重複」、「キーによるデータの取り出し」により分類されます。
データの格納に対して順序性を持つコレクションで、データの格納は最後に、データの取り出しは先頭からといったように、先入先出しを実現します。また、データの格納に対して先頭からの位置(Index)を指定したデータの格納や、取り出しもできます。
データの格納に対して順序性を持たないコレクションで、データの格納は任意の位置に行われます。もっとも特徴的なのは、同じ値を持つデータを格納することは出来ないことです。
格納しているデータをキーにマッピングすることが出来るコレクションで、データの格納は任意の位置に行われます。もっとも特徴的なのは、キーによるデータの格納、取り出しが行えることで、任意取出しを可能としています。
Set の機能に対してデータの値による順序性を持つコレクションで、データの格納は決められた順序が保障される位置に行われます。
前記したインタフェースはデータの集合体をあらわすものですが、よく使用されるインターフェースとして Iterator(イテレーター)があります。これは、コレクション内のデータを先頭から1つづつシーケンシャルに取り出すもので、データ取り出し専用の窓口といえます。Iterator を利用することで、コレクションの実装(集合体の構造)に影響されることなく、統一的なデータ取り出し方法が可能となります。なお、Iterator は GoF のデザインパターンに対応していることでも有名です。
コレクションの機能を実際に実現している実装クラスは多岐にわたり、これらはその利用方法によって最適に動作するようにチューニングされています。
Vector, Stack, Hashtable は、Java 2以前から存在した古いクラスで、コレクション・フレームワークで改良されていまが、データ構造の最大の問題で処理速度が遅いといわれています。その原因は、オブジェクトが常に同期化されることに由来します。
コレクション・クラスは要素をObject型で出し入れします。そのため、取り出した要素を使うためには、目的の型へキャストする必要があります。
Vectorなどの同期がとられるスレッド・セーフなオブジェクトはパフォーマンスが悪く、Java 2で追加されたコレクション・クラスでは同期がとられないようになっています。
Vectorなどの古いクラスでは、後方互換のために、Java 2以前のAPIを実装しています。また、要素を順番に取り出すために、EnumerationとIteratorの両方が使えますが、新しいクラスではIteratorだけしか使えません。
同期化とは、一つのオブジェクトが最大でも一つのスレッドだけから操作されるように実装することです。マルチスレッドでは、オブジェクトに対する同期化は、データを安全に保護する優れた手法なのですが、クラス生成/解放と並んでJavaの実行速度を下げる代表格です。コレクション・フレームワークでは、データ構造オブジェクトは同期をとらないように変更されました。必要なときだけ同期化することで、無用なパフォーマンス低下を回避できます。