selectJava集合实现的经验法则?
任何人都有一个很好的经验法则来selectJava Collection接口的不同实现,比如List,Map或Set吗?
例如,一般为什么或在什么情况下我会喜欢使用Vector或ArrayList,Hashtable或HashMap?
我总是根据具体情况根据具体情况做出这些决定,例如:
- 我需要订单吗?
- 我会有空键/值? DUPS?
- 它会被多个线程访问吗?
- 我需要一个键/值对吗?
- 我需要随机访问吗?
然后我在一个简单的例子中分解出我的方便的第5版Java ,比较大约20个选项。 在第五章里有一些很好的小表来帮助你弄清楚什么是合适的。
好吧,也许如果我知道一个简单的ArrayList或HashSet将做的伎俩,我不会看起来这一切。 ;)但是,如果有任何关于我的使用的复杂的东西,你打赌我在书中。 顺便说一句,我虽然vector应该是'老帽子' – 我没用多年。
我真的很喜欢Sergiy Kovalchuk的博客文章中的备忘单:
更详细的是亚历山大Zagniotov从他的网站的stream程图 。
我会假设你知道上面的答案中的List,Set和Map之间的区别。 为什么你会select他们的实施class是另一回事。 例如:
列表 :
- ArrayList检索速度快,但插入速度慢。 对于一个读取很多但不会插入/删除很多的实现来说,这是非常好的。 它将数据保存在一个连续的内存块中,因此每次需要扩展时都会复制整个数组。
- LinkedList检索速度慢,但插入速度很快。 插入/删除很多但不会读取很多的实现是很好的。 它不会将整个数组保存在一个连续的内存块中。
组:
- HashSet不能保证迭代的顺序,因此是最快的集合。 它的开销很高,比ArrayList慢,所以当散列速度成为一个因素时,除了大量的数据外,你不应该使用它。
- TreeSet保持数据有序,因此比HashSet慢。
Map: HashMap和TreeMap的性能和行为与Set实现是平行的。
Vector和Hashtable不应该被使用。 在发布新的Collection层次结构之前,它们是同步的实现,因此速度很慢。 如果需要同步,请使用Collections.synchronizedCollection()。
理论上有很多有用的Big-Oh权衡,但实际上这些几乎都不重要。
在现实世界的基准testing中,即使列表很大, ArrayList
可以执行LinkedList
,而像“在前端附近有大量的插入”操作。 学术界忽视了这样一个事实,即真正的algorithm具有可以压倒渐近曲线的恒定因素。 例如,链接列表需要为每个节点分配一个额外的对象,这意味着创build一个节点的速度会慢一些,而内存访问特性也会差得多。
我的规则是:
- 总是从ArrayList和HashSet和HashMap(即不是LinkedList或TreeMap)开始。
- types声明应该总是一个接口(即List,Set,Map),所以如果一个分析器或代码审查certificate,否则你可以改变实现而不会破坏任何东西。
关于你的第一个问题
列表,地图和设置服务不同的目的。 我build议阅读关于Java集合框架在http://java.sun.com/docs/books/tutorial/collections/interfaces/index.html 。
为了更具体一些:
- 如果需要类似数组的数据结构,则需要使用List,并且需要迭代元素
- 如果你需要像字典一样的东西,使用地图
- 如果只需要确定是否属于该集合,则使用集合。
关于你的第二个问题
Vector和ArrayList的主要区别在于前者是同步的,后者是不同步的。 您可以阅读更多关于Java并发实践中的同步。
Hashtable(注意T不是大写字母)和HashMap是相似的,前者是同步的,后者是不同步的。
我会说,对于一个实现或者另一个实现,没有经验法则,这取决于你的需求。
对于非sorting的最佳select,十个以上的九个以上将是:ArrayList,HashMap,HashSet。
Vector和Hashtable是同步的,因此可能会慢一些。 你很less会想要同步的实现,当你做他们的接口不够丰富的同步是有用的。 在Map的情况下,ConcurrentMap增加了额外的操作来使界面有用。 ConcurrentHashMap是ConcurrentMap的一个很好的实现。
LinkedList几乎不是一个好主意。 即使你正在做大量的插入和删除操作,如果你正在使用一个索引来指示位置,那么需要遍历列表来find正确的节点。 ArrayList几乎总是更快。
对于Map和Set,散列variables将比树/sorting更快。 散列algortihms往往有O(1)performance,而树木将O(日志n)。
列表允许重复的项目,而集合只允许一个实例。
每当我需要执行查找时,我都会使用Map。
对于具体的实现,有地图和集合的顺序保存变化,但很大程度上取决于速度。 我倾向于使用ArrayList合理的小列表和HashSet合理的小集合,但有很多的实现(包括你自己写的任何)。 HashMap对于Maps来说很常见。 任何超过“相当小”的东西,你必须开始担心内存,所以这将是更具体的algorithm。
如果你对硬编码感兴趣的话, 这个页面有很多animation图像,还有示例代码testingLinkedList和ArrayList。
编辑:我希望下面的链接演示如何这些东西真的只是在工具箱中的项目,你只需要考虑你的需求是什么:请参阅Commons-Collections版本的地图 , 列表和设置 。
我发现布鲁斯·艾克尔(Bruce Eckel)的“Thinking in Java”非常有帮助。 他比较不同的collections非常好。 我曾经把他发表的一张图表作为一个快速参考,显示了我的立方体墙上的inheritance性质。 我build议你做的一件事是牢记线程安全。 性能通常意味着不是线程安全。
正如其他答案中所build议的,根据使用情况,有不同的场景可以使用正确的集合。 我列举了几点,
数组列表:
- 大多数情况下,你只需要存储或迭代“一堆事物”,然后遍历它们。 基于索引的迭代速度更快。
- 每当你创build一个ArrayList,一个固定数量的内存被分配给它,一旦超出,它复制整个数组
链表:
- 它使用双向链表,因此插入和删除操作将会很快,因为它只会添加或删除一个节点。
- 检索速度慢,因为它将不得不遍历节点。
HashSet的:
-
对某个项目做出其他肯定的决定,例如“这个项目是一个英文单词”,“是数据库中的项目? ,“是这个类别的项目吗?” 等等
-
记住“你已经处理了哪些项目”,例如在进行networking抓取时;
HashMap的:
- 用于需要说“给定X,Y是多less”的情况? 对于实现内存中的caching或索引(如键值对)通常很有用。例如:对于给定的用户ID,它们的caching名称/用户对象是什么?
- 始终使用HashMap执行查找。
Vector和Hashtable是同步的,因此位速度较慢,如果需要同步,则使用Collections.synchronizedCollection()。 检查这个sorting的集合。 希望这个hepled。