Java HashMap、TreeMap或LinkedHashMap哪一个迭代最快?
我有一张Java HashMap、TreeMap或LinkedHashMap哪一个迭代最快?,java,collections,iteration,Java,Collections,Iteration,我有一张地图,在启动应用程序时填写。在应用程序执行期间,它不会在以后更改。稍后,此映射仅用于迭代其中的所有元素。我应该选择Map的哪个具体实现HashMap或TreeMap或LinkedHashMap? 更新 插入顺序无关紧要。唯一重要的是所有元素的快速迭代(比如6000个元素)。HashMap通常是最快的,因为它具有最好的缓存行为(HashMap直接在备份数组上迭代,而TreeMap和LinkedHashMap在链接数据结构上迭代) 如果地图初始化后不会更改,您可能需要使用or。我同意Zim
地图
,在启动应用程序时填写。在应用程序执行期间,它不会在以后更改。稍后,此映射仅用于迭代其中的所有元素。我应该选择Map
的哪个具体实现HashMap
或TreeMap
或LinkedHashMap
?更新
插入顺序无关紧要。唯一重要的是所有元素的快速迭代(比如6000个元素)。
HashMap
通常是最快的,因为它具有最好的缓存行为(HashMap
直接在备份数组上迭代,而TreeMap
和LinkedHashMap
在链接数据结构上迭代)
如果地图初始化后不会更改,您可能需要使用or。我同意Zim Zam的回答,并添加一些内容:如果您需要在迭代过程中访问键和值,最快的方法是使用方法,如前所述
现在,如果您确定地图永远不会改变,为什么不使用单独的数据结构进行迭代呢?例如:在完成的映射上迭代一次,并在相同的对应位置用其内容填充两个数组,一个用键,另一个用值。然后遍历这些数组将尽可能快。如果您的映射只用于迭代元素,并且迭代速度很重要,那么将映射转换为ArrayList并在其上迭代,这将是最快的方法。这里的其他答案都没有考虑CPU缓存的影响,当涉及迭代时,它可能是巨大的 改进这一点的一种方法是只使用一个交错键和值的数组(偶数索引的键,奇数索引的值)。这将把这些数据项紧密地组合在一起,并最大限度地利用缓存,至少对于引用是这样
但是,如果您可以避免创建保存数据的对象,而只使用原始值数组,那么真正的、令人尖叫的改进将会实现。当然,这在很大程度上取决于您的用例。我不会使用地图。如果您只想对条目进行迭代,则创建一个新的
ArrayList
,列出您需要的内容并使用它-对于迭代,您的速度不可能超过ArrayList
// Which map you use only chooses the order of the list.
Map<Key,Value> map = new HashMap<>();
// The list to iterate for maximum speed.
List<Map.Entry<Key,Value>> list = new ArrayList<>(map.entrySet());
//使用哪个映射只选择列表的顺序。
Map Map=newhashmap();
//要以最大速度迭代的列表。
List List=newarraylist(map.entrySet());
这样,您只需在条目集上迭代一次即可构建列表。从那时起,您将一次又一次地在列表中进行迭代,这当然应该接近最优
注意根据Marko的建议,从LinkedList
更改为ArrayList
。地图。forEach(双消费者)几乎总是比迭代器快,有时甚至比迭代器快很多。例如,如果对值求和:
public class TestForStackOverflow {
int sum = 0;
// Or whatever Map you are using
Map<Object, Integer> map = new HashMap();
static class C implements BiConsumer<Object, Integer> {
int sum = 0;
@Override
public void accept(Object k, Integer v) {
sum += v;
}
}
public int getSum(Map map) {
C c = new C();
map.forEach(c);
return c.sum;
}
public int getSum2(Map map) {
map.forEach((k, v) -> sum += v);
return sum;
}
}
公共类TestForStackOverflow{
整数和=0;
//或者你用的任何地图
Map Map=newhashmap();
静态类C实现双消费者{
整数和=0;
@凌驾
公共void接受(对象k,整数v){
总和+=v;
}
}
公共整数getSum(映射){
C=新的C();
图.forEach(c);
返回c.sum;
}
公共int getSum2(地图){
映射forEach((k,v)->sum+=v);
回报金额;
}
}
从Java 10开始,您可以使用Map.of()
重载方法或Map.copyOf()
创建一个。由于这些方法返回的映射不支持将任何新条目放入映射中,因此现有的键/值以交错模式存储,如中所述。这将为您的用例提供最佳性能。插入顺序无关紧要。唯一重要的是所有元素的快速迭代(比如说6000个元素)。考虑编辑你的帖子,而不是给它添加注释,这很容易错过。请发表你的结果。@ TrasoHoo:我不明白你的意思。请澄清。如何将HashMap
转换为ArrayList
?Arraylist
将如何存储Hashmap
的键值对?@Mac遍历Map
的entrySet()
,并将键值复制到键值数组中,如我的回答所示。@Mac-简单。创建一个类来保存您的键和值,然后创建该类的ArrayList…@radai该类已经存在,它是映射中内部使用的条目
-在任何非映射的上下文中使用Map.Entry(比如他从映射切换到列表)这是否意味着Hashmap
的entrySet()
方法获得的集合的迭代器将比树映射的更快?我知道Hashmap
中的insert
和search
比Treemap
快,但我想知道Iterator
在这两种情况下的性能them@Mac不,这意味着如果使用entrySet()
返回的集合,遍历映射的速度会更快。另一个问题是,遍历HashMap
可能比遍历从HashMap
的entrySet()。但是,我可以保证HashMap
性能会更快吗?您应该运行一个探查器,亲自查看,这是唯一可以确定的方法。我是根据我对类的内部知识来估计相对速度的,但是有很多因素在起作用——不要