web-dev-qa-db-ja.com

最も効率的なJavaコレクションライブラリは何ですか?

最も効率的なJavaコレクションライブラリは何ですか?

数年前、私は多くのJavaを実行し、当時は trove が最高(最も効率的)Javaであるという印象を持ちました。 _コレクションの実装。しかし、「 最も便利な無料Javaライブラリ? 」という質問への回答を読んだとき、 trove ほとんど言及されていません。では、どのJavaコレクションライブラリが最適ですか?

UPDATE:明確にするために、何百万ものエントリをハッシュテーブルなどに保存する必要があるときに使用するライブラリを主に知りたいランタイムとメモリフットプリント)。

135
Frank

検査から、Troveはプリミティブ型のコレクションのライブラリにすぎないように見えます。JDKの通常のコレクションに多くの機能を追加することを意図しているわけではありません。

個人的に(そして私は偏見がある)私は大好き Guava (以前のGoogle Java Collectionsプロジェクトを含む)。それは、さまざまなタスク(コレクションを含む)を、コレクション操作が私のコードでボトルネックを形成することはめったにないので(私の経験では)、これはより効率的かもしれないがコードを読みやすくしないコレクションAPIよりも「良い」です。

TroveとGuavaのオーバーラップがほとんどないことを考えると、おそらくコレクションライブラリから実際に探しているものを明確にすることができます。

72
Jon Skeet

問題は、(現在)大量のデータを格納することです。これらのデータは、マップにintなどのプリミティブ型を使用して表すことができます。ここでの回答のいくつかは、私の意見では非常に誤解を招くものです。理由を見てみましょう。

trove からベンチマークを変更して、ランタイムとメモリ消費の両方を測定しました。また、このベンチマークに [〜#〜] pcj [〜#〜] を追加しました。これは、プリミティブ型の別のコレクションライブラリです(これを広範囲に使用しています)。 「公式の」Troveベンチマークは、IntIntMapsをJavaコレクションのMap<Integer, Integer>と比較しません。おそらくIntegersを格納することとintsを格納することは技術的な観点からは異なります。ユーザーはこの技術的な詳細を気にしないかもしれませんが、intsで表現可能なデータを効率的に保存したいと考えています。

まず、コードの関連部分:

new Operation() {

     private long usedMem() {
        System.gc();
        return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
     }

     // trove
     public void ours() {
        long mem = usedMem();
        TIntIntHashMap ours = new TIntIntHashMap(SET_SIZE);
        for ( int i = dataset.size(); i-- > 0; ) {
           ours.put(i, i);
        }
        mem = usedMem() - mem;
        System.err.println("trove " + mem + " bytes");
        ours.clear();
     }

     public void pcj() {
        long mem = usedMem();
        IntKeyIntMap map = new IntKeyIntOpenHashMap(SET_SIZE);
        for ( int i = dataset.size(); i-- > 0; ) {
           map.put(i, i);
        }
        mem = usedMem() - mem;
        System.err.println("pcj " + mem + " bytes");
        map.clear();
     }

     // Java collections
     public void theirs() {
        long mem = usedMem();
        Map<Integer, Integer> map = new HashMap<Integer, Integer>(SET_SIZE);
        for ( int i = dataset.size(); i-- > 0; ) {
           map.put(i, i);
        }
        mem = usedMem() - mem;
        System.err.println("Java " + mem + " bytes");
        map.clear();
     }

データはプリミティブintsとして来ると思いますが、これは正気のようです。しかし、これはJava utilの実行時ペナルティを意味します。これは、プリミティブなコレクションフレームワークには必要ない自動ボクシングのためです。

WinXP、jdk1.6.0_10でのランタイムの結果(もちろんgc()呼び出しなし):

 100000 put操作100000には操作が含まれます
 Javaコレクション1938 ms 203 ms 
 trove 234 ms 125 ms 
 pcj 516 ms 94 ms 

これはすでに抜本的に思えるかもしれませんが、これがそのようなフレームワークを使用する理由ではありません。

その理由は、メモリのパフォーマンスです。 100000 intエントリを含むマップの結果:

 Javaコレクションは6644536〜7168840バイトの間で振動します
 trove 1853296バイト
 pcj 1866112バイト

Javaコレクションは、プリミティブコレクションフレームワークと比較して4倍以上のメモリを必要とします。つまりディスクIOにより実行時のパフォーマンスが大幅に低下します。これは重要です。これは重要です。理由は、 高スケーラビリティ を参照してください。

私の経験では、高いメモリ消費はJavaの最大のパフォーマンスの問題であり、当然、ランタイムパフォーマンスも低下します。プリミティブコレクションフレームワークはここで本当に役立ちます。

だから:いいえ、Java.utilは答えではありません。そして、「機能を追加する」Javaコレクションは、効率について尋ねるポイントではありません。また、最新のJDKコレクションは、not特別なTroveコレクション」。

免責事項:ここでのベンチマークは完全とはほど遠いものであり、完璧でもありません。私が多くのプロジェクトで経験したポイントを家に戻すことを意図しています。プリミティブコレクションは、魚のようなAPIを許容するのに十分役立ちます-if大量のデータを扱う場合。

103
the.duckman

私はこれが古い投稿であり、ここにたくさんの答えがあることを知っています。しかし、上記の答えは表面的であり、ライブラリを提案するという点では単純化されています。ここに示されているさまざまなベンチマークでうまく機能するライブラリはありません。私が導き出す唯一の結論は、パフォーマンスとメモリ、特にプリミティブ型を扱うことに関心がある場合、jdk以外の選択肢を見るだけの価値があるということです。

ベンチマークの仕組みとカバーされているライブラリの観点から、より適切な分析を次に示します。 これ は、mahout devリストのスレッドです。

カバーされるライブラリは

  • HPPC
  • トローブ
  • FastUtil
  • マハウト(コルト)
  • Javaコレクション

2015年6月更新:残念ながら、元のベンチマークはもう利用できず、少し古くなっています。 ここ は、他の誰かによって行われたかなり最近(2015年1月)のベンチマークです。元のリンクほど包括的ではなく、インタラクティブな探索ツールもありません。

45
smartnut007

他のコメンテーターが気づいているように、「効​​率的」の定義は広いネットをキャストします。しかし、まだ誰も Javolutionライブラリ について言及していません。

ハイライトのいくつか:

  • Javolutionクラスは高速で、非常に高速です(たとえば、標準のStringBuffer/StringBuilderのO [n]ではなく、O [Log(n)]でのテキストの挿入/削除)。
  • すべてのJavolutionクラスは、リアルタイムに厳密に準拠しており、非常に確定的な動作(マイクロ秒範囲)を持っています。さらに(標準ライブラリとは異なり)、JavolutionはRTSJで安全です(Java Real-Time extension)で使用した場合、メモリクラッシュやメモリリークはありません)。
  • Javolutionのリアルタイムコレクションクラス(マップ、リスト、テーブル、セット)は、ほとんどの標準コレクションクラスの代わりに使用でき、追加の機能を提供します。
  • Javolutionコレクションは、並列アルゴリズムの実装を容易にする同時実行性の保証を提供します。

Javolutionディストリビューションにはベンチマークスイートが含まれているため、他のライブラリ/ビルトインコレクションと比較することができます。

19
sstock

考慮すべきいくつかのコレクションライブラリ:

私は何よりもまず、JDKコレクションライブラリに手を伸ばします。それはあなたがする必要がある最も一般的な事柄をカバーし、明らかにあなたにはすでに利用可能です。

Googleコレクションは、おそらくJDK以外では最高の高品質ライブラリです。頻繁に使用され、十分にサポートされています。

Apache Commons Collectionsは古く、「料理人が多すぎる」という問題に少し悩まされていますが、役に立つものもたくさんあります。

Troveには、プリミティブキー/値などのケース向けの非常に特殊なコレクションがあります。最近では、最新のJDKで、Java 5+コレクションと同時使用ケースを使用すると、JDKコレクションは専用のTroveコレクションよりも優れていることがわかります。

同時実行のユースケースが本当に高い場合は、ロックフリーの実装であり、適切なユースケースがある場合はConcurrentHashMapを踏むことができる、大規模なlibのNonBlockingHashMapのようなものを必ずチェックアウトする必要があります。

15
Alex Miller

何百万ものStringをマップに保存するには、 http://code.google.com/p/flatmap をご覧ください。

6
akuhn

Java.util

明らかな答えで申し訳ありませんが、ほとんどの用途では、デフォルトの Java Collections で十分です。

6
Yuval Adam

私は source-forgeのhappy-collections からのhappy-collectionsの開発者です

  1. イベントベースのコレクション
  2. 変更不可
  3. SortedList
  4. キャッシュ
4

Troveにはいくつかの利点があります。

  • メモリフットプリントが小さく、Map.Entryオブジェクトを使用しません
  • マップのキーの代わりにハッシュ戦略を使用できます。これによりメモリが節約され、新しい属性セットのオブジェクトをキャッシュするたびに新しいキーを定義する必要がなくなります
  • プリミティブコレクションタイプがあります
  • 何らかの形式の内部イテレータがあると思う

とはいえ、Troveが書かれてからjdkコレクションを改善するために多くのことが行われてきました。

しかし、それが私にとって魅力的なのはハッシュ戦略です... Googleがその概要を読んで読んでいます。

3
paul

ConcurrentHashMap およびJava.util.concurrentパッケージは、複数のスレッドでHashMapを使用する場合に言及する必要があります。これは標準Javaの一部であるため、小さなメモリフットプリントが保証されます。

3

「効率的」をどのように定義するかに依存します。

すべてのデータ構造には、読み取り、書き込み、反復、メモリフットプリントなどの独自のBig-Oh動作があります。1つのライブラリ内のリンクリストは、他のライブラリと同じである可能性があります。そして、ハッシュマップは、リンクリストO(n)よりもO(1))を読む方が高速です。

しかし、「最も便利な無料Javaライブラリ?」という質問に対する答えを読んだとき、私はtroveがほとんど言及されていないことに気付きました。

これは「最も効率的」とは思えません。私には「最も人気がある」ように聞こえます。

ほんの少しのフィードバック-私はそれを聞いたことがなく、私はそれを使った人を知りません。 JDK、Google、またはApache Commonsに組み込まれているコレクションは、よく知られています。

3
duffymo

ハッシュテーブルに数百万のレコードを格納する場合、メモリの問題に遭遇する可能性があります。これは、たとえば230万のStringオブジェクトを含むマップを作成しようとしたときに起こりました。 BerkeleyDB を使用しました。これは非常に成熟しており、パフォーマンスも良好です。コレクションAPIをラップするJava APIがあるため、メモリフットプリントがほとんどない任意の大きなマップを簡単に作成できます。ただし、ディスクに保存されるため、アクセスは遅くなります。

フォローアップの質問:不変のコレクションのための、きちんとした(そして効率的な)、よく維持されたライブラリはありますか? Clojureにはこれに対する優れたサポートがあり、Javaにも同様のものがあればいいと思います。

2
fred-o