最も効率的なJavaコレクションライブラリは何ですか?[閉まっている]


135

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

数年前、私は多くのJavaを実行し、当時、その群れが最高の(最も効率的な)Javaコレクション実装であるという印象を持っていました。しかし、「最も有用な無料のJavaライブラリー」という質問に対する回答を読んだとき、私はtroveについてほとんど言及されていないことに気づきました。それでは、どのJavaコレクションライブラリが今最高ですか?

更新:明確にするために、何百万ものエントリをハッシュテーブルなどに格納する必要があるときに使用するライブラリを知りたいと思っています(小さなランタイムとメモリフットプリントが必要です)。


この表のキーと値は何ですか?それらがプリミティブでない場合、通常のHashMapなどの何が問題になっていますか?
ジョンスキート

非常に大きなマップの場合、プローブの実装が必要な場合や、データベーステーブルのようにインライン化する場合もあります。
トムホーティン-タックライン2009年

1
興味深いことに、ここでコルトについての言及はありません。
smartnut007

4
非常に素晴らしいコレクションライブラリ-GSコレクション(github.com/goldmansachs/gs-collections)について言及する価値があります。それは優秀ドキュメントや可変と不変colectionsの徹底的なセットがある
ピョートルKochański

回答:


73

調べてみると、Troveはプリミティブ型のコレクションのライブラリにすぎないようです。JDKの通常のコレクションに多くの機能を追加するためのものではありません。

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

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


3
@Andreas:同意することはできません。「どちらか一方」のシナリオではありません。通常のコレクションを(Listsクラスのようなヘルパーと共に)使用し、必要に応じてIterablesなどを使用します。それがあなたを助けるときだけ、複雑さを使ってください。
Jon Skeet、

10
GCを広範囲に使用してから数か月後に自分のコメントを読んだ後-私は私の過去の意見に同意せず、あなたの意見にも完全に同意します。ヘルパーメソッド/クラスを広範囲に使用すると、コードの多くがより読みやすく安全になります。
Andreas Petersson

1
@Andreas:戻って来てくれてありがとう-GJCが助けてくれてうれしい:)
Jon Skeet

2
ねえ、ジョン、Google JavaコレクションはGuavaになりました。今後の参考のために投稿を更新することもできます:)
Artur Czajka '25年

1
コレクションが大きなボトルネックになっているデータ集約型のプロジェクトにかなり取り組んできました。特にプリミティブを格納している場合、Javaコレクションは(メモリと速度の両方で)非常に非効率的です。
ジェイアスクレン2014

104

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

ベンチマークをtroveから変更して、ランタイムとメモリ消費の両方を測定しました。また、このベンチマークにPCJを追加しました。これは、プリミティブ型の別のコレクションライブラリです(これを広範囲に使用しています)。「公式」のtroveベンチマークはIntIntMapsをJava Collectionと比較していません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の実行時のペナルティを意味します。

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

                      100000のputオペレーション100000にはオペレーションが含まれます 
Javaコレクション1938 ms 203 ms
トローブ234ミリ秒125ミリ秒
pcj 516 ms 94 ms

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

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

Javaコレクションが6644536から7168840バイトの間で変動する
trove 1853296バイト
pcj 1866112バイト

Javaコレクションは、プリミティブコレクションフレームワークに比べて3倍以上のメモリを必要とします。つまり、実行時のパフォーマンスを大幅に低下させるディスクIOに頼ることなく、3倍のデータをメモリに保持できます。そして、これは重要です。理由については、スケーラビリティご覧ください。

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

だから:いいえ、java.utilは答えではありません。また、Javaコレクションに「機能を追加する」ことは、効率性について尋ねるときのポイントではありません。また、最新のJDKコレクションは「特殊化されたTroveコレクションでもパフォーマンスを向上させる」ことができませ

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


3
実際、あなたの答えは誤解を招くものだと思います。intとintegerの格納は非常に異なり、メモリ使用量が増加する主な理由と考えられます。生の型コレクションフレームワークは便利かもしれませんが、それはjava.utilよりもtroveやpcjを「より良く」しません。
ジョーン

22
問題は、intデータを効率的に格納することです。整数の格納についてではありません。このタスクでは、私が示したようにtrove / pcjの方が効率的です。整数を使用すると、ランタイムとメモリの効率が低下します。java.utilではプリミティブを使用できないため、このタスクには最適ではありません。
the.duckman 2009年

2
(ロシアのコミュニティのための)ここで別のベンチマーク行く:total-holywar.blogspot.com/2011/07/...
dma_k

intをキーとして使用しないかどうかはわかりません。通常の文字列だけです。それらのワークベンチの結果はどうなりますか?
クラークバオ

@ClarkBao(遅れて申し訳ありません)キーとしてオブジェクトを保存すると、そのオブジェクトが使用されますhashCode()。それはintキーとしてあなたを取得します。
Matthieu 14

47

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

ここでは、ベンチマークのメカニズムと対象となるライブラリの観点から、より適切な分析を行います。 これは、mahout devリストのスレッドです。

対象となるライブラリは

  • HPPC
  • Trove
  • FastUtil
  • Mahout(コルト)
  • Javaコレクション

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


1
ありがとうございました。これは非常に役に立ちました。質問の重要性を考えると、(duckman以外の)他の回答が実際にこの質問に答えているとは信じがたいです。
デクスター

20

他のコメンテーターが気づいたように、「効​​率的」の定義は幅広いネットを投げかけます。ただし、Javolutionライブラリについてはまだ誰も触れていません。

ハイライトのいくつか:

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

Javolutionディストリビューションにはベンチマークスイートが含まれているため、他のライブラリや組み込みのコレクションとどのように比較されるかを確認できます。


16

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

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

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

Apache Commons Collectionは古く、「料理人が多すぎる」問題に少し悩まされていますが、便利な機能もたくさんあります。

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

非常に高い同時実行のユースケースがある場合は、ロックのない実装であり、適切なユースケースがある場合はConcurrentHashMapに踏み込むことができる、大規模なlibのNonBlockingHashMapなどを確実にチェックする必要があります。


7
「最近の私たちは、最新のJDK、およびJava 5+コレクションと同時使用ケースで、JDKコレクションが特殊なTroveコレクションよりも優れていることを発見しました。」誤解を招く-私は、Troveのような特殊なプリミティブコレクションクラスでプリミティブ型を格納/取得することが、メモリ使用量とCPU時間の両方でJDKコレクションクラスを上回らなかったマイクロベンチマークを見たことがない。(プリミティブ型ではなく)オブジェクトを使用している場合は、Alexに同意します。コレクションの実装に関するフレッティングはそれほど大きな問題ではありません。
リヤドカラ

2
このステートメントは、以前にTroveコレクションを必要としていたが、今はそれを引き出すことができたさまざまなコレクションimplの実際の使用状況(私はいつでもマイクロベンチマークを引き継ぐ)に基づいています。JDK 6の後半の更新(2009年後半頃)は、Integerなどの一般的なマップキーのカスタムコードを実際に提供し、最も一般的な用途のいくつかを大幅に改善しました。
Alex Miller、

1
アレックス、特定のユースケースでは、プリミティブコレクションを引き出してJDKコレクションを処理するのに十分な速さであったことは間違いありませんが、コレクションであるランドスケープ全体に手を振り、「すべてのパスが完了しました。それで十分です。 」正確ではありません。私が2Dゲームエンジンで作業している場合、プリミティブ型を常にボックス化/ボックス化解除するオーバーヘッドは、かなり高くつきます。REST APIを使用している場合は、いいえ、おそらく、HTTP I / Oなどのはるかに高価な操作に関して、測定可能な違いはまったくありません。あなたの投稿をすべて定量化することを余儀なくされました。
リヤドカラ

4
これを読んでいる誰もが私たちのどちらかに耳を傾けるべきではないと思います。彼らは彼ら自身のユースケースをテストし、何が最高のパフォーマンスを持っているかを見るべきです。私のコメントは、さまざまなライブラリを使用したチームのかなり積極的なパフォーマンステストに基づいています。YMMV。
Alex Miller、

2
@Riyadに同意します。私は高性能有限オートマトンスイートを作成していて、それをTroveとJava Collections Framework(jdk 6最新アップデート)の両方で実装しました。Troveは大いに優れています。計算速度とメモリ消費の両方で数十倍のオーダーです。
Nico Huysamen、2011

6

java.util

明白な答えで申し訳ありませんが、ほとんどの用途では、デフォルトのJavaコレクションで十分です。


4
基本的な使用については、はい。しかし、私は、フレームワークは、(不変コレクション、フィルタ、multimapの、などなど)いくつかの基本的な機能と高度な機能をミスし、(例えば)Googleのコレクションの出番それはだと思う
ジョーン

1
この答えは要点を逃していると思います。JCFはおそらく人々があまりJavaを使わなかった2002年には最高でした。残念ながら、特に他のJVM言語からのコレクションのサポートと比較すると、十分に老化していません。
Ted Pennings、2011年

3
-1質問は「intを格納するのに最も効率的」であり、前述の例はjava.utilより優れています
kommradHomer '25 / 10/25



3

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


3

「効率的」の定義方法によって異なります。

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

しかし、「最も有用な無料のJavaライブラリー」という質問への回答を読んだとき。トローブはほとんど言及されていないことに気づきました。

これは「最も効率的」なようには聞こえません。「一番人気」のようです。

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


3

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

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

そうは言っても、troveが作成されて以来、jdkコレクションを改善するために多くのことが行われてきました。

それは私にとって魅力的なハッシング戦略です...グーグルのためにそれらの概要を読んでください。


2

数百万のレコードをハッシュテーブルに格納する場合、メモリの問題が発生する可能性があります。これは、たとえば230万個のStringオブジェクトでマップを作成しようとしたときに起こりました。私は一緒に行ったのBerkeleyDB。これは非常に成熟していて、パフォーマンスが優れています。それらには、コレクションAPIをラップするJava APIがあるため、メモリフットプリントが非常に少ない任意の大きなマップを簡単に作成できます。ただし、アクセスは遅くなります(ディスクに格納されるため)。

フォローアップの質問:不変のコレクションのためのまともな(そして効率的な)、よく管理されたライブラリはありますか?Clojureはこれに優れたサポートを提供しており、Javaにも同様の機能があると便利です。


1
Googleコレクションは不変のコレクションを追加します。
the.duckman 2009年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.