はじめに
何年も前のことですが、私が初めてJavaに興味を覚えた理由の1つは、Javaプラットフォームに標準でコレクションライブラリが組み込まれていたからでした。当時、C++の世界ではまだSTL(Standard Template Library)が定着しておらず、開発者たちは適当なコレクションライブラリを購入して利用するか(Rogue Waveが流行っていました)、自分の手でライブラリを書くしかありませんでした。正確な数は忘れましたが、私自身も、さまざまな目的でさまざまな種類のプリミティブやオブジェクトの連結リストを実装しました。さらに、もっと複雑なコレクションや平衡2分探索木、ハッシュテーブルなども自分で実装しました。そのようにしてソフトウェア工学の原理を絶えず意識することは決して無駄なことでありませんでしたが、生産性を考えるとそうとばかりも言えませんでした。
しかし、Javaによって事態はまったく変わりました。バージョン1.0と1.1のコレクションクラスでも大きな改善が見られましたが、Java 1.2で導入されたJava Collections Frameworkは生産性を飛躍的に高めるものでした。以来、標準コレクションは拡張と改良を幾度となく繰り返し、Java 5で新たにジェネリックス(Generics)が導入されたことを受けて、(少なくともコンパイル時には)型検査をしたいと考える人々に好んで使われるようになりました。Doug Leaの並列処理コレクションの導入も歓迎されました。これがJava 5以降のJava.util.concurrentに組み込まれたことで、並列処理システムに適したQueueやConcurrentMapのようなコレクションを利用できるようになりました。
それにもかかわらず標準コレクションには欠点があります。アイテムがたびたび再実装され、ときにはとても最適とは言えないやり方が使われることもあります。また弱点もあります。ジェネリックス(少なくともJavaにおけるその実装)の費用対効果は目下議論されているところですが、好きか嫌いかは別としてジェネリックスが非常に冗長なものであることは間違いありません。たとえば、2003年当時はコレクションが次のようなスタイルで書かれていました。
Map mapOfLists = new HashMap();
ところが現在は、何かをリストにマップするとき、次のようなスタイルが使われます。
Map<String, List<String>> mapOfLists =
new HashMap<String, List<String>>();
これは必ずしも公正な比較ではありません。2番目の定義の方がコンパイル用の情報を多く含んでおり、キーにはString型のみが用いられること、そしてHashMapの値にはString型のListが用いられることをJavaコンパイラに伝えているからです。とはいえ、お気づきのように同じ情報が幾度となく繰り返され、その定義やさらに初期化の際にも型シグニチャが繰り返されるなど、あまり美しいとは言えません。
Google Collections Libraryは、GoogleがJavaコミュニティ向けに提供する新たなオープンソースライブラリです。Javaの現在のコレクションが抱える扱いにくさを漸進的に改善することと、独自のコレクションや機能を新たに付け加えることを目指しています。しかし同じ道を進むのはこれだけでなく、当然Apache Commons Collectionsとの比較も必要でしょう。コレクション増強ライブラリとしてどれを選ぶかは概して趣味の問題です。本稿では、Google Collections Libraryを取り上げることにします。私はこのライブラリを(内部的な形ながら)Googleのいくつかのプロジェクトで1年以上使ってみて、かなりよくできていると感じたからです。感触的にはJava Collections Frameworkが自然に発展したものと見ることができ、その高い信頼性と能力、そして何もかもが開示されている点を評価すると、今後のプロジェクトにこれなしで取り組むことなど到底考えられません。幸い、現在オープンソースプロジェクトとして提供されていることからすれば、そのような心配は無用のようです。
Google Collections Libraryを使う理由
言うまでもなく、以下に挙げる理由は主観的なものです。それでも、Java Collections Frameworkのコレクション増強ライブラリとしてGoogle Collections Libraryを採用することには、それ相応の理由があります。
- 今すぐ使える: 現在のバージョンは0.5 alphaですが、これはGoogle社外での使われ方を見て今後ライブラリを改良するためにAPIが変更される可能性がある、という意味です。このバージョン番号とステータスを文字通り受け取って、まだ多くのバグがあるとか、今使うのは早計であるとか判断するのは正しくありません。このライブラリのコードはGoogle社の多くの大規模なプロジェクトで実際に一定期間テストされたものであり、きわどい症例はほぼ出尽くしたと見てよいでしょう。テストカバレッジも85%に達しています。無論、APIは今後まだ変更される可能性があり、それを懸念する気持ちも理解できますが、実際に変更があったとしても小さなもので、簡単に対処できると思われます(保証はできませんが)。それでもやはり不安という方は、ライブラリのステータスに目を光らせ、APIが安定するまで待ってください。
- 一貫性がある: 実際に使ってみて、このライブラリの新しいコレクションと、新たに加わった使い勝手のよい機能は、どちらもJava Collections Frameworkの自然な発展形であるように感じられます。偶然の産物ではありません。Javaのコレクションと動作レベルで一貫性を持たせるために多くの労力が投入された結果であり、しかもSunにおける実装の現場でJavaのコレクションを実際に扱った技術者(たとえば、Josh Bloch)が、その作業を監督しているという事実を見落としてはいけません。特に、ジェネリックスはJava Collections Frameworkと完全に同じ方法で扱われています。
- 大きさが手頃: 新たな機能を実装したjarファイルのサイズは約350 KBで、たいていのプロジェクトで問題とされるような値ではありません。
- ドキュメントが充実: このライブラリのJavadocはどこから見ても完璧であり、この種のライブラリとしては特に優れています。
- 高性能: これらのコレクションは、性能を重視するGoogle社のプロジェクトでそのまま利用されており、最大限の性能を引き出すために多くの労力が投入されてきました。
- 新機能: コレクションを多用するシステムを意識して、使い勝手を考慮した改良や実用的なアイデアが実装されています。たとえば、コレクションの出力結果をフィルタリングする機能や、制約を適用する機能があります。
公平を期するため、このライブラリを使うことで生じるかもしれない問題も指摘しておきます。
- このライブラリの補助クリエータ(convenience creators)は、Java 7に向けて提案されている型推論と折り合いがよくありません。そのため、このライブラリを利用した場合、将来的に初期化コードの一部を書き換えなければならなくなるかもしれません。あるいは、2つの標準を抱えたまま進む道を選ばざるを得なくなるかもしれません。
- これらのコレクションの一部、あるいはそこに含まれるアイデアがJava 7またはJava 8の開発タイムフレームの中でJSRとして1つか2つ提案されることはあるかもしれませんが、多くはそうならないでしょう。つまり、これらのコレクションを今利用するということは、将来それらを標準規格とするための労力が発生するかもしれないことを意味します。
- 既に述べたように、APIはまだ変更される可能性があります。