我有一个Map
,在应用程序启动时填充。在应用程序执行过程中不会更改此映射表。稍后,此地图仅用于迭代其中的所有元素。我应该选择哪个具体实现的Map
?HashMap
、TreeMap
还是LinkedHashMap
?
更新
插入顺序并不重要。唯一重要的是快速迭代所有元素(比如6000个元素)。
我有一个Map
,在应用程序启动时填充。在应用程序执行过程中不会更改此映射表。稍后,此地图仅用于迭代其中的所有元素。我应该选择哪个具体实现的Map
?HashMap
、TreeMap
还是LinkedHashMap
?
更新
插入顺序并不重要。唯一重要的是快速迭代所有元素(比如6000个元素)。
HashMap
通常会更快,因为它具有最好的缓存行为(HashMap
直接迭代支持数组,而TreeMap
和LinkedHashMap
则迭代链接数据结构)。
如果地图在初始化后不会改变,则可以使用ImmutableMap或UnmodifiableMap。
HashMap
的决定。你对这种情况有什么建议? - Mac这里的其他答案都没有考虑到CPU缓存的影响,而当涉及迭代时,这可能是巨大的。
改进的一种方法是仅使用一个交错键值数组(偶数索引处为键,奇数索引处为值)。这将紧密地组合这些数据项并最大限度地利用缓存,至少对于引用来说是如此。
但是,如果您可以避免创建保存数据的对象并仅使用原始值数组,则真正的、显著的改进将会实现。这自然取决于您的用例。
int[]
可能会产生回报。如果您真的想要最后一点性能,您将不得不对这些替代方案进行基准测试。 - Marko Topolnikjmh
这样的微基准工具。否则,您几乎肯定会得到不恰当的结果。是的,性能是一个艰难的主题,需要大量的知识、经验和直觉。它没有捷径可走。 - Marko TopolnikIterator
中的CPU缓存,你是想表达Iterator
在迭代之前会在CPU寄存器中内部缓存key-value
对吗?还是我理解错了? - Mac我不会使用地图。如果您只想遍历条目,请制作所需内容的新的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。
ArrayList
获得观察到的加速,则使用它,但是您将占用更多内存。 LinkedList
将添加最小的内存开销。 - OldCurmudgeonLinkedList
是最浪费的:它为每个列表节点分配一个完整的对象。ArrayList
只有一个数组,自然地,如果您正在从现有映射转换,可以将其大小调整到合适的大小。但是我的建议是使用普通数组而不是 ArrayList
。对于固定列表,你真的不会从 ArrayList
获得任何好处。 - Marko TopolnikHashMap
转换为ArrayList
?一个ArrayList
如何存储HashMap
的键值对? - MacMap
内部使用的Map.Entry
。 - Óscar LópezentrySet()
方法,如此处所讨论。Hashmap
的entrySet()
方法获得的集合的Iterator
比TreeMap
的更快?我知道在Hashmap
中进行插入
和搜索
比Treemap
更快,但我想了解它们两者的Iterator
性能。 - MacentrySet()
返回的集合,遍历Map会更快。另一件事是,遍历HashMap
可能比遍历TreeMap
更快。 - Óscar LópezHashMap
зљ„entrySet()
иҺ·еЏ–зљ„Iterator
еЏҮиѓҢдәљж›өеү«пәЊе› дёғе®ѓењЁе†…йѓЁе®һзҺ°зљ„ж–№еәЏдёҚеђЊгЂ‚ - Óscar LópezHashMap
的性能会更快? - MacMap.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;
}
}