什么是最有效的Java Collections库?
几年前,我做了很多Java的工作,给人留下的印象是那个宝库是最好(最有效)的Java Collections实现。但是,当我阅读“ 最有用的免费Java库? ” 这个问题的答案时,我注意到几乎没有提到trove。那么,哪个Java Collections库现在最好?
更新:为澄清起见,我主要想知道当我必须在哈希表等中存储数百万个条目时使用哪个库(需要小的运行时和内存占用)。
什么是最有效的Java Collections库?
几年前,我做了很多Java的工作,给人留下的印象是那个宝库是最好(最有效)的Java Collections实现。但是,当我阅读“ 最有用的免费Java库? ” 这个问题的答案时,我注意到几乎没有提到trove。那么,哪个Java Collections库现在最好?
更新:为澄清起见,我主要想知道当我必须在哈希表等中存储数百万个条目时使用哪个库(需要小的运行时和内存占用)。
Answers:
从检查的角度看,Trove似乎只是原始类型的集合的库-并不是要在JDK的正常集合上添加很多功能。
就个人而言(我有偏见),我喜欢Guava(包括以前的Google Java Collections项目)。它以一种至少相当有效的方式简化了各种任务(包括集合)。考虑到收集操作很少会形成代码瓶颈(以我的经验),这比收集API“更好”,后者可能更有效,但不会使我的代码具有可读性。
考虑到Trove和Guava之间的重叠几乎为零,也许您可以从收藏库中弄清楚您真正想要的东西。
现在的问题是关于存储大量数据,这些数据可以使用诸如 int
Map中的。在我看来,这里的一些答案是非常令人误解的。让我们看看为什么。
我从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放置操作100000包含操作 Java集合1938毫秒203毫秒 234毫秒125毫秒 pcj 516毫秒94毫秒
尽管这似乎已经很严峻,但这并不是使用这种框架的原因。
原因是内存性能。包含100000 int
个条目的Map的结果:
Java集合在6644536和7168840字节之间振荡 trove 1853296字节 pcj 1866112字节
与原始集合框架相比,Java集合需要的内存是其三倍以上。也就是说,您可以在内存中保留三倍的数据,而无需诉诸于磁盘IO,这会严重降低运行时性能。这很重要。阅读可扩展性以了解原因。
以我的经验,高内存消耗是Java的最大性能问题,这当然也会导致运行时性能下降。原始收集框架确实可以在这里提供帮助。
因此:不,java.util不是答案。在询问效率时,向Java集合“添加功能”并不是重点。同样,现代的JDK集合也不 “超越专业的Trove集合”。
免责声明:这里的基准还远远不够完善,也不是完美的。我要在很多项目中都经历过这一点。如果您处理大量数据,则原始集合足够有用以容忍可疑的API 。
hashCode()
。它使您int
成为关键。
我知道这是一篇旧文章,并且这里有很多答案。但是,上述建议是肤浅的,在建议图书馆方面过于简化。在这里介绍的各种基准测试中,没有一个库能很好地完成工作。我得出的唯一结论是,如果您关心性能和内存,尤其是处理原始类型,则值得考虑使用非jdk替代方案。
就基准机制和所涵盖的库而言,这是一个更合理的分析。 这是mahout开发人员列表中的一个线程。
涵盖的库是
2015年6月更新:不幸的是,原始基准不再可用,而且有点过时了。 这是其他人最近完成的基准测试(2015年1月)。它不像原始链接那样全面,也没有交互式探索工具。
正如其他评论员所注意到的那样,“有效”的定义产生了广泛的影响。但是还没有人提到Javolution库。
一些亮点:
Javolution发行版包括一个基准套件,因此您可以查看它们如何与其他库/内置集合进行堆叠。
需要考虑的一些收集库:
我首先要接触JDK集合库。它涵盖了您需要做的最常见的事情,并且显然已经为您所用。
Google馆藏可能是JDK之外最好的高质量库。它得到了广泛的使用和良好的支持。
Apache Commons Collections比较老,并且受“厨师太多”问题的影响,但也有很多有用的东西。
Trove对于诸如原始键/值之类的案例有非常专业的集合。这些天来,我们发现在现代JDK上以及Java 5+集合和并发用例中,JDK集合甚至胜过专门的Trove集合。
如果您确实有很高的并发用例,则绝对应该在高级lib中检出NonBlockingHashMap之类的东西,它是无锁的实现,如果您有合适的用例,可以在ConcurrentHashMap上sto脚。
java.util
很抱歉,答案很明显,但是对于大多数用途,默认的Java Collections绰绰有余。
要String
在地图上存储数百万个,请查看http://code.google.com/p/flatmap
我是source-forge上happy-collection的happy-collection的开发人员
java.util.concurrent
如果计划在多个线程中使用HashMap,则应提及ConcurrentHashMap 以及程序包。由于这是标准Java的一部分,因此保证了较小的内存占用。
如果要在哈希表中存储数百万条记录,则很可能会遇到内存问题。例如,当我尝试使用230万个String对象创建地图时,这发生了。我去了BerkeleyDB,它非常成熟并且性能良好。它们具有包装Collections API的Java API,因此您可以轻松创建占用很少内存的任意大地图。但是访问速度会变慢(因为它存储在磁盘上)。
后续问题:是否有一个像样的(高效的),维护良好的,用于不可变集合的库?Clojure为此提供了出色的支持,并且对Java有类似的支持也将是一件很高兴的事情。