我有一个Map
,它在应用程序启动期间被填满。在执行应用程序期间,它不会在以后更改。之后,此映射仅用于迭代其中的所有元素。我应该选择Map
的具体实施方案? HashMap
或TreeMap
或LinkedHashMap
?
的更新
广告订单无关紧要。唯一重要的是快速迭代所有元素(比如6000个元素)。
答案 0 :(得分:10)
HashMap
通常最快,因为它具有最佳缓存行为(HashMap
直接在后备阵列上迭代,而TreeMap
和LinkedHashMap
遍历链接数据结构)。
如果地图初始化后不会改变,您可能需要使用ImmutableMap或UnmodifiableMap
答案 1 :(得分:6)
这里没有其他答案考虑到CPU缓存的影响,当涉及迭代时,它可以巨大。
改善这种情况的一种方法是仅使用单个交错键和值数组(偶数索引处的键,奇数处的值)。这将紧密地将这些数据项组合在一起,并最大限度地利用缓存,至少对于引用来说。
但是,如果您可以避免创建保存数据的对象并仅使用原始值数组,那么可以实现真正的,尖锐的改进。当然,这很大程度上取决于您的使用案例。
答案 2 :(得分:4)
我不会使用地图。如果你想要的只是迭代条目,你需要一个新的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());
这样,您只需遍历条目集一次即可构建列表。从那时起,你一次又一次地遍历列表 - 这当然应该接近最优。
注意在Marko的建议下从LinkedList
更改为ArrayList
。
答案 3 :(得分:3)
如果您的地图仅用于迭代元素并且迭代速度很重要,那么将地图转换为ArrayList并迭代它,这将是最快的方法。
答案 4 :(得分:1)
我同意Zim-Zam的回答,并添加一些内容:如果您需要在迭代期间同时访问键和值,最快的方法是使用entrySet()
方法,如here所述。
现在,如果您确定地图永远不会改变,为什么不使用单独的数据结构进行迭代?例如:在完成的地图上迭代一次,并在相同的相应位置填充其内容的几个数组,一个带有键,另一个带有值。然后遍历这些数组将尽可能快。
答案 5 :(得分:0)
从Java 10开始,您可以使用Map.of()
重载方法之一,也可以使用Map.copyOf()
创建unmodifiable Map。由于这些方法返回的映射不支持在映射中放入任何新条目,因此现有的键/值以this answer中所述的交织模式存储。这应该为您的用例提供最佳性能。
答案 6 :(得分:-2)
Map.forEach(BiConsumer)几乎总是比迭代器更快,有时甚至更大。如果您将值汇总为例如:
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;
}
}