什么是最有效的Java Collections库?

时间:2009-03-10 11:48:07

标签: java collections

什么是最有效的Java Collections库?

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

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

12 个答案:

答案 0 :(得分:102)

问题是(现在)关于在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上的运行时结果(当然没有gc()调用),jdk1.6.0_10:

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

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

原因是内存性能。包含100000个int条目的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 - 如果您使用大量数据。

答案 1 :(得分:72)

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

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

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

答案 2 :(得分:45)

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

在基准力学和所涵盖的图书馆方面,这是一个更健全的分析。 This是mahout开发列表中的一个主题。

所涵盖的图书馆是

  • HPPC
  • 特罗韦
  • FastUtil
  • Mahout(柯尔特)
  • Java Collections

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

答案 3 :(得分:19)

正如其他评论员所注意到的那样,“高效”的定义投入了广泛的网络。然而,还没有人提到Javolution library

一些亮点:

  • Javolution类快速,非常快(例如,在O [Log(n)]中插入/删除文本而不是标准StringBuffer / StringBuilder的O [n]。
  • 所有Javolution类都是硬实时兼容的,并且具有高度确定性的行为(在微秒范围内)。此外(与标准库不同),Javolution是RTSJ安全的(与Java Real-Time扩展一起使用时没有内存冲突或内存泄漏)。
  • Javolution的实时集合类(map,list,table和set)可用于代替大多数标准集合类,并提供其他功能。
  • Javolution集合提供并发保证,使并行算法的实现更容易。

Javolution发行版包含一个基准测试套件,因此您可以看到它们如何与其他库/内置集合进行叠加。

答案 4 :(得分:15)

要考虑的一些集合库:

我首先要到达JDK集合库。它涵盖了您需要做的最常见的事情,显然已经可以使用了。

Google Collections可能是JDK之外最好的高质量库。它使用频繁且得到很好的支持。

Apache Commons Collections年龄较大,受到“太多厨师”问题的影响,但也有很多有用的东西。

Trove拥有非常专业的集合,适用于原始键/值等案例。现在,我们发现在现代JDK和Java 5+集合以及并发用例中,JDK集合甚至超过了专门的Trove集合。

如果你有很高的并发用例,你一定要在高规模的lib中检查像NonBlockingHashMap这样的东西,这是一个无锁的实现,如果你有合适的用例,它可以踩踏ConcurrentHashMap。

答案 5 :(得分:6)

<强> java.util

很抱歉显而易见的答案,但对于大多数用途,默认Java Collections绰绰有余。

答案 6 :(得分:6)

要在地图中存储数百万String,请查看http://code.google.com/p/flatmap

答案 7 :(得分:4)

我是来自happy-collections on source-forge

的快乐收藏品的开发者
  1. 基于事件的收藏
  2. 不可修改
  3. 排序列表
  4. 高速缓存

答案 8 :(得分:3)

如果您计划在多个线程中使用HashMap,则应提及

ConcurrentHashMap以及java.util.concurrent包。因为这是标准java的一部分,所以会有很小的内存占用。

答案 9 :(得分:3)

取决于我们如何定义“高效”。

每个数据结构都有自己的Big-Oh行为,用于读取,写入,迭代,内存占用等。一个库中的链表可能与其他任何一个相同。读取O(1)的哈希映射比链表O(n)更快。

  

但是当我读到“最有用的免费Java库?”这个问题的答案时。我注意到很难提到这个问题。

这听起来不像“最有效”。这对我来说听起来像“最受欢迎”。

只是一些反馈 - 我从来没有听说过,而且我不知道有谁使用过它。 JDK,Google或Apache Commons中内置的集合对我来说是众所周知的。

答案 10 :(得分:3)

Trove提供了一些优势。

  • 内存占用较小,不使用Map.Entry对象
  • 您可以使用哈希策略代替地图键,这可以节省内存,这意味着每次要在一组新属性上缓存对象时都不需要定义新密钥
  • 它有原始的集合类型
  • 认为它有某种形式的内部迭代器

也就是说,自从编写了trove之后,已经做了很多工作来改进jdk集合。

它的散列策略让我对它很有吸引力... Google for trove并阅读他们的概述。

答案 11 :(得分:2)

如果要在哈希表中存储数百万条记录,可能会遇到内存问题。例如,当我尝试创建一个包含230万个String对象的地图时,就发生了这种情况。我和BerkeleyDB一起去了,这是非常成熟的,表现很好。他们有一个包装Collections API的Java API,因此您可以轻松创建任意大的映射,而内存占用很少。但访问速度会慢(因为它存储在磁盘上)。

后续问题:对于不可变集合,是否有一个体面(且高效),维护良好的库? Clojure对此有很好的支持,为Java提供类似的东西会很好。