如果我有一个用Java实现Map接口的对象,并且我希望对其中包含的每一对进行迭代,那么最有效的方法是什么?
元素的顺序是否取决于我对接口的特定映射实现?
如果我有一个用Java实现Map接口的对象,并且我希望对其中包含的每一对进行迭代,那么最有效的方法是什么?
元素的顺序是否取决于我对接口的特定映射实现?
当前回答
对于Eclipse集合,您将在MapIterable接口上使用forEachKeyValue方法,该方法由MutableMap和ImmutableMap接口及其实现继承。
MutableMap<Integer, String> map =
Maps.mutable.of(1, "One", 2, "Two", 3, "Three");
MutableBag<String> result = Bags.mutable.empty();
map.forEachKeyValue((key, value) -> result.add(key + value));
MutableBag<String> expected = Bags.mutable.of("1One", "2Two", "3Three");
Assertions.assertEquals(expected, result);
将forEachKeyValue与EclipseCollections(EC)Map实现一起使用比使用entrySet更有效的原因是因为EC Map实现不存储Map.Entry对象。将entrySet与EC Map实现一起使用会动态生成Map.Entry对象。forEachKeyValue方法能够避免创建Map.Entry对象,因为它可以直接导航Map实现的内部结构。在这种情况下,使用内部迭代器比使用外部迭代器有好处。
注意:我是Eclipse集合的提交人。
其他回答
如果我有一个用Java实现Map接口的对象,并且我希望对其中包含的每一对进行迭代,那么最有效的方法是什么?
如果循环键的效率是应用程序的优先事项,那么选择一个Map实现,以您所需的顺序维护键。
元素的顺序是否取决于我对接口的特定映射实现?
是的,绝对。
一些Map实现承诺一定的迭代顺序,而其他的则没有。Map的不同实现维护键值对的不同顺序。
请参见我创建的总结了与Java11捆绑的各种Map实现的表。具体来说,请注意迭代顺序列。单击/轻按以缩放。
您可以看到,有四个Map实现维护一个顺序:
树图并发跳过列表映射链接的哈希映射EnumMap(枚举映射)
NavigableMap界面
其中两个实现NavigableMap接口:TreeMap&ConcurrentSkipListMap。
旧的SortedMap界面被新的NavigableMap界面有效地取代。但您可能会发现第三方实现仅实现旧接口。
自然秩序
如果您想要一个按键的“自然顺序”排列其对的Map,请使用TreeMap或ConcurrentSkipListMap。术语“自然顺序”是指实现Comparable的键类。compareTo方法返回的值用于排序中的比较。
自定义订单
如果要为键指定自定义排序例程以用于维护排序顺序,请传递适合于键类的Comparator实现。使用TreeMap或ConcurrentSkipListMap,传递比较器。
原始插入顺序
如果您希望映射对保持在它们插入映射的原始顺序,请使用LinkedHashMap。
枚举定义顺序
如果使用诸如DayOfWeek或Month之类的枚举作为键,请使用EnumMap类。这个类不仅被高度优化以使用很少的内存并且运行非常快,它还按照枚举定义的顺序维护您的对。例如,对于DayOfWeek,DayOfWeek.MONDAY的键将在迭代时首先找到,DayOfWeek.SUNDAY的密钥将是最后一个。
其他注意事项
在选择Map实现时,还应考虑:
NULLs。某些实现禁止/接受NULL作为键和/或值。并发性。如果要跨线程操作映射,则必须使用支持并发的实现。或者使用Collections::synchronizedMap包装映射(不太可取)。
以上图表中涵盖了这两个考虑因素。
如果您通过Map进行迭代的原因是对值执行操作并写入结果Map。我建议在GoogleGuavaMaps类中使用转换方法。
import com.google.common.collect.Maps;
将地图添加到导入后,可以在地图上使用Maps.transformValues和Maps.transform Entries,如下所示:
public void transformMap(){
Map<String, Integer> map = new HashMap<>();
map.put("a", 2);
map.put("b", 4);
Map<String, Integer> result = Maps.transformValues(map, num -> num * 2);
result.forEach((key, val) -> print(key, Integer.toString(val)));
// key=a,value=4
// key=b,value=8
Map<String, String> result2 = Maps.transformEntries(map, (key, value) -> value + "[" + key + "]");
result2.forEach(this::print);
// key=a,value=2[a]
// key=b,value=4[b]
}
private void print(String key, String val){
System.out.println("key=" + key + ",value=" + val);
}
如果您有一个通用的非类型映射,可以使用:
Map map = new HashMap();
for (Map.Entry entry : ((Set<Map.Entry>) map.entrySet())) {
System.out.println(entry.getKey() + "/" + entry.getValue());
}
有很多方法可以做到这一点。下面是几个简单的步骤:
假设您有一张地图,如:
Map<String, Integer> m = new HashMap<String, Integer>();
然后,您可以执行以下操作来迭代地图元素。
// ********** Using an iterator ****************
Iterator<Entry<String, Integer>> me = m.entrySet().iterator();
while(me.hasNext()){
Entry<String, Integer> pair = me.next();
System.out.println(pair.getKey() + ":" + pair.getValue());
}
// *********** Using foreach ************************
for(Entry<String, Integer> me : m.entrySet()){
System.out.println(me.getKey() + " : " + me.getValue());
}
// *********** Using keySet *****************************
for(String s : m.keySet()){
System.out.println(s + " : " + m.get(s));
}
// *********** Using keySet and iterator *****************
Iterator<String> me = m.keySet().iterator();
while(me.hasNext()){
String key = me.next();
System.out.println(key + " : " + m.get(key));
}
我用以下代码将地图数据复制到另一个地图:
HashMap product =(HashMap)shopping_truck.get(i);
HashMap tmp = new HashMap();
for (Iterator it = product.entrySet().iterator(); it.hasNext();) {
Map.Entry thisEntry = (Map.Entry) it.next();
tmp.put(thisEntry.getKey(), thisEntry.getValue());
}