如果我有一个用Java实现
元素的顺序是否依赖于接口的特定映射实现?
1 2 3 4 |
为了总结其他的答案并将它们与我所知道的结合起来,我找到了10种主要的方法来做到这一点(见下文)。此外,我还编写了一些性能测试(参见下面的结果)。例如,如果我们想找到一个map中所有键值的和,我们可以这样写:
使用iterator和Map.Entry
1 2 3 4 5 6 |
使用foreach和Map.Entry
1 2 3 4 |
使用Java 8中的forEach
1 2 | final long[] i = {0}; map.forEach((k, v) -> i[0] += k + v); |
使用keySet和foreach
1 2 3 4 |
使用键集和迭代器
1 2 3 4 5 6 | long i = 0; Iterator<Integer> itr2 = map.keySet().iterator(); while (itr2.hasNext()) { Integer key = itr2.next(); i += key + map.get(key); } |
使用for和Map.Entry
1 2 3 4 5 |
使用Java 8流API
1 2 | final long[] i = {0}; map.entrySet().stream().forEach(e -> i[0] += e.getKey() + e.getValue()); |
使用Java 8流API并行
1 2 | final long[] i = {0}; map.entrySet().stream().parallel().forEach(e -> i[0] += e.getKey() + e.getValue()); |
使用
1 2 3 4 5 | long i = 0; MapIterator<Integer, Integer> it = iterableMap.mapIterator(); while (it.hasNext()) { i += it.next() + it.getValue(); } |
使用Eclipse (CS)集合的MutableMap
1 2 3 4 | final long[] i = {0}; mutableMap.forEachKeyValue((key, value) -> { i[0] += key + value; }); |
性能测试(模式=平均时间,系统= windows 8.1 64位,Intel i7-4790 3.60 GHz, 16 GB)
对于小地图(100个元素),得分0.308是最好的
1 2 3 4 5 6 7 8 9 10 11 | Benchmark Mode Cnt Score Error Units test3_UsingForEachAndJava8 avgt 10 0.308 ± 0.021 μs/op test10_UsingEclipseMap avgt 10 0.309 ± 0.009 μs/op test1_UsingWhileAndMapEntry avgt 10 0.380 ± 0.014 μs/op test6_UsingForAndIterator avgt 10 0.387 ± 0.016 μs/op test2_UsingForEachAndMapEntry avgt 10 0.391 ± 0.023 μs/op test7_UsingJava8StreamApi avgt 10 0.510 ± 0.014 μs/op test9_UsingApacheIterableMap avgt 10 0.524 ± 0.008 μs/op test4_UsingKeySetAndForEach avgt 10 0.816 ± 0.026 μs/op test5_UsingKeySetAndIterator avgt 10 0.863 ± 0.025 μs/op test8_UsingJava8StreamApiParallel avgt 10 5.552 ± 0.185 μs/op |
对于10000个元素的map,得分37.606是最好的
1 2 3 4 5 6 7 8 9 10 11 | Benchmark Mode Cnt Score Error Units test10_UsingEclipseMap avgt 10 37.606 ± 0.790 μs/op test3_UsingForEachAndJava8 avgt 10 50.368 ± 0.887 μs/op test6_UsingForAndIterator avgt 10 50.332 ± 0.507 μs/op test2_UsingForEachAndMapEntry avgt 10 51.406 ± 1.032 μs/op test1_UsingWhileAndMapEntry avgt 10 52.538 ± 2.431 μs/op test7_UsingJava8StreamApi avgt 10 54.464 ± 0.712 μs/op test4_UsingKeySetAndForEach avgt 10 79.016 ± 25.345 μs/op test5_UsingKeySetAndIterator avgt 10 91.105 ± 10.220 μs/op test8_UsingJava8StreamApiParallel avgt 10 112.511 ± 0.365 μs/op test9_UsingApacheIterableMap avgt 10 125.714 ± 1.935 μs/op |
对于包含100000个元素的map,得分1184.767是最好的
1 2 3 4 5 6 7 8 9 10 11 | Benchmark Mode Cnt Score Error Units test1_UsingWhileAndMapEntry avgt 10 1184.767 ± 332.968 μs/op test10_UsingEclipseMap avgt 10 1191.735 ± 304.273 μs/op test2_UsingForEachAndMapEntry avgt 10 1205.815 ± 366.043 μs/op test6_UsingForAndIterator avgt 10 1206.873 ± 367.272 μs/op test8_UsingJava8StreamApiParallel avgt 10 1485.895 ± 233.143 μs/op test5_UsingKeySetAndIterator avgt 10 1540.281 ± 357.497 μs/op test4_UsingKeySetAndForEach avgt 10 1593.342 ± 294.417 μs/op test3_UsingForEachAndJava8 avgt 10 1666.296 ± 126.443 μs/op test7_UsingJava8StreamApi avgt 10 1706.676 ± 436.867 μs/op test9_UsingApacheIterableMap avgt 10 3289.866 ± 1445.564 μs/op |
图(根据地图大小进行性能测试)
表(性能测试取决于映射大小)
1 2 3 4 5 6 7 8 9 10 11 | 100 600 1100 1600 2100 test10 0.333 1.631 2.752 5.937 8.024 test3 0.309 1.971 4.147 8.147 10.473 test6 0.372 2.190 4.470 8.322 10.531 test1 0.405 2.237 4.616 8.645 10.707 test2 0.376 2.267 4.809 8.403 10.910 test7 0.473 2.448 5.668 9.790 12.125 test9 0.565 2.830 5.952 13.220 16.965 test4 0.808 5.012 8.813 13.939 17.407 test5 0.810 5.104 8.533 14.064 17.422 test8 5.173 12.499 17.351 24.671 30.403 |
所有测试都在GitHub上。
在Java 8中,您可以使用新的lambdas特性快速而干净地完成它:
1 2 3 4 5 6 |
编译器将推断
非常简单!
是的,顺序取决于特定的Map实现。
@ScArcher2具有更优雅的Java 1.5语法。在1.4中,我会这样做:
1 2 3 4 5 6 7 |
迭代映射的典型代码是:
1 2 3 4 5 6 |
(更新:我认为这不再是真的。)注意,
使用迭代器和泛型的例子:
1 2 3 4 5 6 7 |
这是一个由两部分组成的问题:
如何迭代Map的条目- @ScArcher2完美地回答了这个问题。
迭代的顺序是什么——如果您只是使用
有几种遍历map的方法。
下面是通过在map中存储一百万对键值对并将遍历map来比较它们对于map中存储的公共数据集的性能。
1)对每个循环使用
1 2 3 4 |
50毫秒
2)对每个循环使用
1 2 3 |
76毫秒
3)使用
1 2 3 4 5 6 |
50毫秒
4)使用
1 2 3 4 5 |
75毫秒
我已经提到
正确的方法是使用公认的答案,因为它是最有效的。我发现下面的代码看起来更简洁一些。
顺便说一下,如果您只对映射的键/值感兴趣,而对其他键/值不感兴趣,您还可以使用
对于Eclipse集合(以前是GS集合),您将在MapIterable接口上使用forEachKeyValue方法,该方法由MutableMap和ImmutableMap接口及其实现继承。
1 2 3 4 5 6 7 8 9 10 | final MutableBag<String> result = Bags.mutable.empty(); MutableMap<Integer, String> map = Maps.mutable.of(1,"One", 2,"Two", 3,"Three"); map.forEachKeyValue(new Procedure2<Integer, String>() { public void value(Integer key, String value) { result.add(key + value); } }); Assert.assertEquals(Bags.mutable.of("1One","2Two","3Three"), result); |
使用Java 8 lambda语法,您可以编写如下代码:
1 2 3 4 | MutableBag<String> result = Bags.mutable.empty(); MutableMap<Integer, String> map = Maps.mutable.of(1,"One", 2,"Two", 3,"Three"); map.forEachKeyValue((key, value) -> result.add(key + value)); Assert.assertEquals(Bags.mutable.of("1One","2Two","3Three"), result); |
注意:我是Eclipse集合的提交者。
用Java 1.4试试:
1 2 3 4 5 6 7 8 |
从理论上讲,最有效的方法将取决于Map的实现方式。正式的方法是调用
在特殊的实现中,使用
是的,顺序将取决于实现——以及(可能)插入的顺序和其他难以控制的因素。
[编辑]我最初写的是
Java 8:
你可以使用lambda表达式:
1 2 3 4 |
要了解更多信息,请按此操作。
与Java 8
1 |
在Map中,你可以迭代
1)。遍历地图的
2)。遍历地图的
1 2 3 |
3)。遍历地图的
1 2 3 4 5 |
此外,有三种不同的方法可以遍历HashMap。他们也一样
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | //1. for (Map.Entry entry : hm.entrySet()) { System.out.print("key,val:"); System.out.println(entry.getKey() +"," + entry.getValue()); } //2. Iterator iter = hm.keySet().iterator(); while(iter.hasNext()) { Integer key = (Integer)iter.next(); String val = (String)hm.get(key); System.out.println("key,val:" + key +"," + val); } //3. Iterator it = hm.entrySet().iterator(); while (it.hasNext()) { Map.Entry entry = (Map.Entry) it.next(); Integer key = (Integer)entry.getKey(); String val = (String)entry.getValue(); System.out.println("key,val:" + key +"," + val); } |
Lambda Expression Java 8
在Java 1.8 (Java 8)中,通过使用来自聚合操作(流操作)的forEach方法,这变得容易得多,该方法看起来类似于来自Iterable接口的迭代器。
只需将下面的语句复制粘贴到代码中,并将HashMap变量从hm重命名为HashMap变量,以打印出键值对。
1 2 3 4 5 6 7 8 9 10 |
下面是我尝试使用Lambda表达式的示例代码。这东西太酷了。必须试一试。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | HashMap<Integer,Integer> hm = new HashMap<Integer, Integer>(); Random rand = new Random(47); int i=0; while(i<5){ i++; int key = rand.nextInt(20); int value = rand.nextInt(50); System.out.println("Inserting key:"+key+" Value:"+value); Integer imap =hm.put(key,value); if( imap == null){ System.out.println("Inserted"); } else{ System.out.println("Replaced with"+imap); } } hm.forEach((k,v) -> System.out.println("key:"+k+" value:"+v)); Output: Inserting key: 18 Value: 5 Inserted Inserting key: 13 Value: 11 Inserted Inserting key: 1 Value: 29 Inserted Inserting key: 8 Value: 0 Inserted Inserting key: 2 Value: 7 Inserted key: 1 value:29 key: 18 value:5 key: 2 value:7 key: 8 value:0 key: 13 value:11 |
同样也可以使用Spliterator。
1 | Spliterator sit = hm.entrySet().spliterator(); |
更新
包括指向Oracle文档的文档链接。有关Lambda的更多信息,请访问此链接并必须读取聚合操作,而对于Spliterator,请访问此链接。
Java 8
我们有一个接受lambda表达式的
1 2 3 |
遍历键:
1 |
遍历值:
1 |
迭代条目(使用forEach和Streams):
1 2 3 4 5 6 |
流的优点是,如果我们想并行化,它们可以很容易地并行化。我们只需要使用
如果你有一个通用的非类型化地图,你可以使用:
1 2 3 4 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public class abcd{ public static void main(String[] args) { Map<Integer, String> testMap = new HashMap<Integer, String>(); testMap.put(10,"a"); testMap.put(20,"b"); testMap.put(30,"c"); testMap.put(40,"d"); for (Integer key:testMap.keySet()) { String value=testMap.get(key); System.out.println(value); } } } |
或
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public class abcd { public static void main(String[] args) { Map<Integer, String> testMap = new HashMap<Integer, String>(); testMap.put(10,"a"); testMap.put(20,"b"); testMap.put(30,"c"); testMap.put(40,"d"); for (Entry<Integer, String> entry : testMap.entrySet()) { Integer key=entry.getKey(); String value=entry.getValue(); } } } |
最紧凑的Java 8:
1 |
1 2 3 4 5 6 |
你可以使用泛型:
1 2 3 4 5 6 |
使用Java 8:
1 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | //Functional Oprations Map<String, String> mapString = new HashMap<>(); mapString.entrySet().stream().map((entry) -> { String mapKey = entry.getKey(); return entry; }).forEach((entry) -> { String mapValue = entry.getValue(); }); //Intrator Map<String, String> mapString = new HashMap<>(); for (Iterator<Map.Entry<String, String>> it = mapString.entrySet().iterator(); it.hasNext();) { Map.Entry<String, String> entry = it.next(); String mapKey = entry.getKey(); String mapValue = entry.getValue(); } //Simple for loop Map<String, String> mapString = new HashMap<>(); for (Map.Entry<String, String> entry : mapString.entrySet()) { String mapKey = entry.getKey(); String mapValue = entry.getValue(); } |
排序将始终依赖于特定的映射实现。使用java&c;8可以使用以下任何一种:
1 |
或者:
1 2 3 |
结果将是相同的(顺序相同)。由地图支持的入口集,所以你得到了相同的顺序。第二个很方便,因为它允许您使用lambdas,例如,如果您只想打印大于5的整数对象:
1 2 3 4 |
下面的代码显示了通过LinkedHashMap和普通HashMap的迭代(示例)。你会看到顺序的不同:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | public class HMIteration { public static void main(String[] args) { Map<Object, Object> linkedHashMap = new LinkedHashMap<>(); Map<Object, Object> hashMap = new HashMap<>(); for (int i=10; i>=0; i--) { linkedHashMap.put(i, i); hashMap.put(i, i); } System.out.println("LinkedHashMap (1):"); linkedHashMap.forEach((k,v) -> { System.out.print(k +" (#="+k.hashCode() +"):" + v +","); }); System.out.println(" LinkedHashMap (2):"); linkedHashMap.entrySet().forEach((e) -> { System.out.print(e.getKey() +" :" + e.getValue() +","); }); System.out.println(" HashMap (1):"); hashMap.forEach((k,v) -> { System.out.print(k +" (#:"+k.hashCode() +"):" + v +","); }); System.out.println(" HashMap (2):"); hashMap.entrySet().forEach((e) -> { System.out.print(e.getKey() +" :" + e.getValue() +","); }); } } |
LinkedHashMap (1):
10 (#=10):10, 9 (#=9):9, 8 (#=8):8, 7 (#=7):7, 6 (#=6):6, 5 (#=5):5, 4 (#=4):4, 3 (#=3):3, 2 (#=2):2, 1 (#=1):1, 0 (#=0):0,
LinkedHashMap (2):
10 : 10, 9 : 9, 8 : 8, 7 : 7, 6 : 6, 5 : 5, 4 : 4, 3 : 3, 2 : 2, 1 : 1, 0 : 0,
HashMap (1):
0 (#:0):0, 1 (#:1):1, 2 (#:2):2, 3 (#:3):3, 4 (#:4):4, 5 (#:5):5, 6 (#:6):6, 7 (#:7):7, 8 (#:8):8, 9 (#:9):9, 10 (#:10):10,
HashMap (2):
0 : 0, 1 : 1, 2 : 2, 3 : 3, 4 : 4, 5 : 5, 6 : 6, 7 : 7, 8 : 8, 9 : 9, 10 : 10,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | package com.test; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.Set; public class Test { public static void main(String[] args) { Map<String, String> map = new HashMap<String, String>(); map.put("ram","ayodhya"); map.put("krishan","mathura"); map.put("shiv","kailash"); System.out.println("********* Keys *********"); Set<String> keys = map.keySet(); for (String key : keys) { System.out.println(key); } System.out.println("********* Values *********"); Collection<String> values = map.values(); for (String value : values) { System.out.println(value); } System.out.println("***** Keys and Values (Using for each loop) *****"); for (Map.Entry<String, String> entry : map.entrySet()) { System.out.println("Key:" + entry.getKey() +"\t Value:" + entry.getValue()); } System.out.println("***** Keys and Values (Using while loop) *****"); Iterator<Entry<String, String>> entries = map.entrySet().iterator(); while (entries.hasNext()) { Map.Entry<String, String> entry = (Map.Entry<String, String>) entries .next(); System.out.println("Key:" + entry.getKey() +"\t Value:" + entry.getValue()); } System.out .println("** Keys and Values (Using java 8 using lambdas )***"); map.forEach((k, v) -> System.out .println("Key:" + k +"\t value:" + v)); } } |
是的,正如许多人所同意的,这是遍历
但是如果地图是
1 2 3 4 5 6 7 8 9 |
有很多方法可以做到这一点。以下是一些简单的步骤:
假设你有一张这样的地图:
然后,您可以执行如下操作来遍历映射元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | // ********** 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)); } |
如果遍历
1 | import com.google.common.collect.Maps; |
在将
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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); } |
映射上有效的迭代解决方案是从Java 5到Java 7的"for each"循环。这里是:
1 2 3 |
从Java 8开始,您可以使用lambda表达式对映射进行迭代。它是一个增强的"forEach"
1 |
If you want to write a conditional for lambda you can write it like this:
1 2 3 4 5 6 |
这里有一个通用的类型安全方法,可以调用它来转储任何给定的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | import java.util.Iterator; import java.util.Map; public class MapUtils { static interface ItemCallback<K, V> { void handler(K key, V value, Map<K, V> map); } public static <K, V> void forEach(Map<K, V> map, ItemCallback<K, V> callback) { Iterator<Map.Entry<K, V>> it = map.entrySet().iterator(); while (it.hasNext()) { Map.Entry<K, V> entry = it.next(); callback.handler(entry.getKey(), entry.getValue(), map); } } public static <K, V> void printMap(Map<K, V> map) { forEach(map, new ItemCallback<K, V>() { @Override public void handler(K key, V value, Map<K, V> map) { System.out.println(key +" =" + value); } }); } } |
例子
下面是一个例子。注意,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | import java.util.*; public class MapPrinter { public static void main(String[] args) { List<Map<?, ?>> maps = new ArrayList<Map<?, ?>>() { private static final long serialVersionUID = 1L; { add(new LinkedHashMap<String, Integer>() { private static final long serialVersionUID = 1L; { put("One", 0); put("Two", 1); put("Three", 3); } }); add(new LinkedHashMap<String, Object>() { private static final long serialVersionUID = 1L; { put("Object", new Object()); put("Integer", new Integer(0)); put("Double", new Double(0.0)); } }); } }; for (Map<?, ?> map : maps) { MapUtils.printMap(map); System.out.println(); } } } |
输出
它并没有完全回答OP的问题,但是对于其他找到这个页面的人可能有用:
如果你只需要值而不需要键,你可以这样做:
1 2 3 4 | Map<Ktype, Vtype> myMap = [...]; for (Vtype v: myMap.values()) { System.out.println("value:" + v); } |
我相信这是最简单的方法。
1 2 3 4 5 6 7 8 9 10 11 12 | /* For example, this could be a map object */ Map<String, Integer> MAP = new Map<>(); // Do something like put keys/value pairs into the map, etc... MAP.put("Denver", 35); MAP.put("Patriots", 14); /* Then, simply use a for each loop like this to iterate */ for (Object o : MAP.entrySet()) { Map.Entry pair = (Map.Entry) o; // Do whatever with the pair here (i.e. pair.getKey(), or pair.getValue(); } |
有几种方法可以迭代映射。请参考以下代码。
使用iterator接口迭代映射时,必须使用条目或entrySet()
它是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | import java.util.*; import java.util.HashMap; import java.util.Iterator; import java.util.Map; public class IteratMapDemo{ public static void main(String arg[]){ Map<String, String> mapOne = new HashMap<String, String>(); mapOne.put("1","January"); mapOne.put("2","February"); mapOne.put("3","March"); mapOne.put("4","April"); mapOne.put("5","May"); mapOne.put("6","June"); mapOne.put("7","July"); mapOne.put("8","August"); mapOne.put("9","September"); mapOne.put("10","Octomber"); mapOne.put("11","November"); mapOne.put("12","December"); Iterator it = mapOne.entrySet().iterator(); while(it.hasNext()) { Map.Entry me = (Map.Entry) it.next(); //System.out.println("Get Key through While loop =" + me.getKey()); } for(Map.Entry<String, String> entry:mapOne.entrySet()){ //System.out.println(entry.getKey() +"=" + entry.getValue()); } for (Object key : mapOne.keySet()) { System.out.println("Key:" + key.toString() +" Value:" + mapOne.get(key)); } } } |
我用这个代码把一张地图的数据复制到另一张地图上:
1 2 3 4 5 6 |
迭代映射非常简单。
例如,您有一个
1 2 3 |
快乐的编码…
如果您想按照元素添加的顺序遍历映射,请使用
这种方法在过去对我很有效:
1 2 3 4 5 6 7 8 |
输出:
1 2 | 69 1337 |