问题

什么是最有效的Java Collections库?

几年前,我做了很多Java并且给人的印象是当时的5998501403是最好的(最有效的)Java Collections实现。但是当我读到问题"Most useful free Java libraries?"的答案时,我注意到很少提到trove。那么哪个Java Collections库现在最好?

**更新:**为了澄清,当我必须在哈希表等中存储数百万个条目时,我主要想知道要使用哪个库(需要小的运行时和内存占用)。


#1 热门回答(99 赞)

问题是(现在)关于存储大量数据,这些数据可以在Map中使用原始类型(如int)表示。在我看来,这里的一些答案非常具有误导性。让我们看看为什么。

我修改了trove的基准来测量运行时和内存消耗。我还在此基准测试中添加了PCJ,这是基本类型的另一个集合库(我广泛使用它)。 "官方"宝库基准测试不会将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的运行时损失,因为自动装箱,这对于原始集合框架来说不是必需的。

WinXP,jdk1.6.0_10上的运行时结果(当然没有gc()calls):

100000 put operations      100000 contains operations 
java collections             1938 ms                        203 ms
trove                         234 ms                        125 ms
pcj                           516 ms                         94 ms

虽然这可能看起来很激烈,但这并不是使用这种框架的原因。

原因是内存性能。包含100000int条目的Map的结果:

java collections        oscillates between 6644536 and 7168840 bytes
trove                                      1853296 bytes
pcj                                        1866112 bytes

与原始集合框架相比,Java集合需要三倍于内存。即你可以在内存中保留三倍的数据,而无需借助磁盘IO,从而降低运行时性能的大小。这很重要。阅读highscalability以找出原因。

根据我的经验,高内存消耗是Java最大的性能问题,这当然也会导致运行时性能下降。原始集合框架在这里可以提供帮助。

所以:不,java.util不是答案。在询问效率时,向Java集合添加"功能"并不是重点。现代JDK系列也是而不是"甚至超过了专门的Trove系列"。

免责声明:这里的基准远非完整,也不完美。这是为了让我在许多项目中经历过这一点。如果使用大量数据,原始集合足以容忍可疑的API -


#2 热门回答(70 赞)

从检查来看,看起来Trove只是一个原始类型的集合库 - 它不像是在JDK中添加了许多正常集合的功能。

个人(我有偏见)我喜欢Guava(包括以前的Google Java Collections项目)。它以一种至少相当有效的方式使各种任务(包括集合)变得更加容易。鉴于集合操作很少在我的代码中形成瓶颈(根据我的经验),这比集合API"更好",集合API可能更有效但不会使我的代码可读。

鉴于Trove和Guava之间的重叠几乎为零,或许你可以从集合库中澄清你实际需要的内容。


#3 热门回答(42 赞)

我知道这是一个老帖子,这里有很多答案。但是,在建议图书馆方面,上面的答案是肤浅的,而且过于简化。没有一个图书馆在这里提供的各种基准测试中表现良好。我得出的唯一结论是,如果你关心性能和内存,特别是处理原始类型,那么它非常值得关注非jdk替代方案。

这是一个更健全的分析,在基准机制和涵盖的库方面.This是mahout开发列表中的一个线程。

涵盖的图书馆是

  • HPPC
  • 特洛伊
  • FastUtil
  • Mahout(柯尔特)
  • Java Collections

2015年6月更新:不幸的是,最初的基准测试不再可用,而且有点过时.Here是其他人完成的最新(2015年1月)基准测试。它不是那么全面,也没有原始链接的交互式探索工具。


原文链接