请参考以下方法:
public Set<LIMSGridCell> getCellsInColumn(String columnIndex){
Map<String,LIMSGridCell> cellsMap = getCellsMap();
Set<LIMSGridCell> cells = new HashSet<LIMSGridCell>();
Set<String> keySet = cellsMap.keySet();
for(String key: keySet){
if(key.startsWith(columnIndex)){
cells.add(cellsMap.get(key));
}
}
return cells;
}
FindBugs给出了这条警告信息:
“低效使用keySet迭代器而不是entrySet迭代器 此方法使用的键访问Map条目的值 从keySet迭代器中检索。使用它更有效 地图的entrySet上的迭代器,以避免Map.get(键) 查找“。
答案 0 :(得分:51)
您正在检索所有键(访问整个地图),然后对于某些键,您再次访问地图以获取值。
您可以遍历地图以获取地图条目(Map.Entry)(一对键和值)并仅访问地图一次。
Map.entrySet()提供了一组Map.Entry
s,其中包含密钥和相应的值。
for ( Map.Entry< String, LIMSGridCell > entry : cellsMap.entrySet() ) {
if ( entry.getKey().startsWith( columnIndex ) ) {
cells.add( entry.getValue() );
}
}
注意:我怀疑这会有很大的改进,因为如果你使用地图条目,你将为每个条目实例化一个对象。我不知道这是否真的比调用get()
并直接检索所需的引用更快。
答案 1 :(得分:12)
如果某人仍然对详细且数字支持的答案感兴趣:是的,您应该使用entrySet()
与keySet()
,以防您迭代整个地图。有关详细数字,请参阅this Gist。我使用JMH运行基准测试,以获得使用Oracle JDK8的Map的默认实现。
主要发现是:迭代keySet
并重新查询每个键总是慢一点。一旦你有更大的地图,乘数就会变得很大(例如,对于ConcurrentSkipListMap
,它总是5-10倍;而对于HashMap
s,它不会超过2倍,高达一百万条目)。
然而,这些仍然是非常小的数字。迭代超过100万个条目的最慢方式是ConcurrentSkipListMap.keySet()
,大约是500-700毫秒;虽然迭代超过IdentityHashMap.entrySet()
只有25-30毫秒而LinkedHashMap.entrySet()
仅落后于40-50毫秒(这并不奇怪,因为它内部有LinkedList
,这有助于迭代)。作为上述链接Gist的概述:
Map type | Access Type | Δ for 1M entries
----------------------+-------------+-----------------
HashMap | .entrySet() | 69-72 ms
HashMap | .keySet() | 86-94 ms
ConcurrentHashMap | .entrySet() | 72-76 ms
ConcurrentHashMap | .keySet() | 87-95 ms
TreeMap | .entrySet() | 101-105 ms
TreeMap | .keySet() | 257-279 ms
LinkedHashMap | .entrySet() | 37-49 ms
LinkedHashMap | .keySet() | 89-120 ms
ConcurrentSkipListMap | .entrySet() | 94-108 ms
ConcurrentSkipListMap | .keySet() | 494-696 ms
IdentityHashMap | .entrySet() | 26-29 ms
IdentityHashMap | .keySet() | 69-77 ms
所以底线是:它取决于你的用例。虽然迭代entrySet()
肯定更快,但数字并不大,特别是对于相当小的地图。但是,如果您经常迭代一个包含100万个条目的Map,那么最好使用更快的方式;)
当然,数字只是为了相互比较,而不是绝对。
答案 2 :(得分:9)
您正在获取地图中的一组键,然后使用每个键从地图中获取值。
相反,您可以简单地遍历通过entrySet()
返回给您的Map.Entry键/值对。这样你就可以避免相对昂贵的get()
查询(注意在这里使用相对这个词)
e.g。
for (Map.Entry<String,LIMSGridCell> e : map.entrySet()) {
// do something with...
e.getKey();
e.getValue();
}
答案 3 :(得分:2)
这是建议;不是你的问题的答案。 当您使用ConcurrentHashMap时;下面是javadoc
中提到的迭代器行为视图的迭代器是一个永远不会的“弱一致”迭代器 抛出ConcurrentModificationException,并保证遍历 在构造迭代器时它们存在的元素,并且可能 (但不保证)反映后续的任何修改 构造
所以如果你使用EntrySet迭代器;这可能包含陈旧的键/值对;所以它会更好;从keySet iterator()获取密钥;并检查集合的价值。这将确保您从集合中获得最近的更改。
如果你对故障安全迭代器没问题;然后查看link;它声明使用entrySet;很少改善表现。
答案 4 :(得分:0)
在密钥集中,您需要获取所有密钥,然后搜索集合中的每个密钥。
此外,在entrySet上循环更快,因为您不会为每个键查询两次映射。
如果只需要键或只需要Map的值,那么请使用keySet()或values()。