提问人:iMack 提问时间:9/6/2008 最后编辑:Barry ChapmaniMack 更新时间:7/5/2023 访问量:3298293
如何有效地遍历 Java Map 中的每个条目?
How do I efficiently iterate over each entry in a Java Map?
答:
是的,顺序取决于具体的 Map 实现。
@ScArcher2 具有更优雅的 Java 1.5 语法。在 1.4 中,我会做这样的事情:
Iterator entries = myMap.entrySet().iterator();
while (entries.hasNext()) {
Entry thisEntry = (Entry) entries.next();
Object key = thisEntry.getKey();
Object value = thisEntry.getValue();
// ...
}
评论
for
for (Entry e : myMap.entrySet)
Iterator
Entry thisEntry = (Entry) entries.next();
Entry
java.util.Map.Entry
Map<String, String> map = ...
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println(entry.getKey() + "/" + entry.getValue());
}
在 Java 10+ 上:
for (var entry : map.entrySet()) {
System.out.println(entry.getKey() + "/" + entry.getValue());
}
评论
remove
map.values()
map.keySet()
从理论上讲,最有效的方法将取决于 Map 的实现。执行此操作的官方方法是调用 ,它返回一组 ,每个 包含一个键和一个值 ( 和 )。map.entrySet()
Map.Entry
entry.getKey()
entry.getValue()
在特殊实现中,使用 还是其他方式可能会有所不同。但我想不出为什么有人会这样写。最有可能的是,它对你所做的事情的性能没有影响。map.keySet()
map.entrySet()
是的,顺序将取决于实现 - 以及(可能)插入顺序和其他难以控制的因素。
[编辑]我最初写的,但当然是答案。valueSet()
entrySet()
遍历地图的典型代码是:
Map<String,Thing> map = ...;
for (Map.Entry<String,Thing> entry : map.entrySet()) {
String key = entry.getKey();
Thing thing = entry.getValue();
...
}
HashMap
是规范映射实现,并且不做保证(或者,如果没有对其执行更改操作,则不应更改顺序)。 将根据键的自然顺序返回条目,如果提供,则返回 。 将按插入顺序或访问顺序返回条目,具体取决于其构造方式。 按键的自然顺序返回条目。SortedMap
Comparator
LinkedHashMap
EnumMap
(更新:我认为这不再是真的。请注意,迭代器当前有一个特殊的实现,它为 !但是,每当新的迭代器前进时,都会更新。IdentityHashMap
entrySet
Map.Entry
entrySet
Map.Entry
评论
LinkedHashMap
iterator
spliterator
entrySet
这是一个由两部分组成的问题:
如何遍历地图的条目 - @ScArcher2完美地回答了这个问题。
迭代的顺序是什么——如果你只是使用 ,那么严格来说,没有排序保证。因此,您不应该真正依赖任何实现给出的顺序。但是,SortedMap
接口扩展并提供了您正在寻找的内容 - 实现将提供一致的排序顺序。Map
Map
NavigableMap
是另一个有用的扩展 - 这是一个附加方法,用于按条目在键集中的有序位置查找条目。因此,这有可能首先消除迭代的需要 - 您也许能够在使用 、 、 或 方法之后找到特定的方法。该方法甚至为您提供了反转遍历顺序的显式方法。SortedMap
entry
higherEntry
lowerEntry
ceilingEntry
floorEntry
descendingMap
仅供参考,如果您只对地图的键/值感兴趣,也可以使用 and,而对其他键/值不感兴趣。map.keySet()
map.values()
正确的方法是使用公认的答案,因为它是最有效的。我发现下面的代码看起来更干净一些。
for (String key: map.keySet()) {
System.out.println(key + "/" + map.get(key));
}
评论
O(1) = 2*O(1)
2
entrySet()
keySet()
Map
2
hashcode % capacity
hashcode % capacity
hashcode
Comparable
O(log n)
Comparable
O(n)
O(1)
使用迭代器和泛型的示例:
Iterator<Map.Entry<String, String>> entries = myMap.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry<String, String> entry = entries.next();
String key = entry.getKey();
String value = entry.getValue();
// ...
}
评论
Iterator
for (Iterator<Map.Entry<K, V>> entries = myMap.entrySet().iterator(); entries.hasNext(); ) { Map.Entry<K, V> entry = entries.next(); }
entries
在 Java 1.4 中尝试以下操作:
for ( Iterator entries = myMap.entrySet().iterator(); entries.hasNext();) {
Entry entry = (Entry) entries.next();
System.out.println(entry.getKey() + "/" + entry.getValue());
//...
}
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);
}
}
}
或
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();
}
}
}
使用 Eclipse Collections,您将在 MapIterable
接口上使用该方法,该方法由 and 接口及其实现继承。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);
与 Eclipse Collections (EC) 实现一起使用比使用更有效的原因是 EC 实现不存储对象。与 EC 实现一起使用会导致动态生成对象。该方法能够避免创建对象,因为它可以直接导航实现的内部结构。在这种情况下,使用内部迭代器比使用外部迭代器有好处。forEachKeyValue
Map
entrySet
Map
Map.Entry
entrySet
Map
Map.Entry
forEachKeyValue
Map.Entry
Map
注意:我是Eclipse Collections的提交者。
是的,正如许多人所同意的那样,这是迭代 .Map
但是如果地图是.别忘了输入 .check。NullPointerException
null
null
|
|
- - - -
|
|
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
}
您可以使用泛型来做到这一点:
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry<Integer, Integer> entry = entries.next();
System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
}
在 Java 8 中,您可以使用新的 lambda 功能干净快速地完成它:
Map<String,String> map = new HashMap<>();
map.put("SomeKey", "SomeValue");
map.forEach( (k,v) -> [do something with key and value] );
// such as
map.forEach( (k,v) -> System.out.println("Key: " + k + ": Value: " + v));
和的类型将由编译器推断,无需再使用。k
v
Map.Entry
简单易行!
评论
map.entrySet().stream()
如果您有一个通用的非类型化 Map,则可以使用:
Map map = new HashMap();
for (Map.Entry entry : ((Set<Map.Entry>) map.entrySet())) {
System.out.println(entry.getKey() + "/" + entry.getValue());
}
有几种方法可以迭代地图。请参考以下代码。
当您使用接口迭代映射时,必须使用 或 .Iterator
Entry<K,V>
entrySet()
它看起来像这样:
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));
}
}
}
评论
在地图中,可以迭代和/或和/或取决于自己感兴趣的in_例如:keys
values
both (e.g., entrySet)
遍历映射的
键 -> keySet():
Map<String, Object> map = ...; for (String key : map.keySet()) { //your Business logic... }
遍历映射的 values
-> values():
for (Object value : map.values()) { //your Business logic... }
遍历映射的
-> entrySet():
for (Map.Entry<String, Object> entry : map.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); //your Business logic... }
此外,有 3 种不同的方法可以遍历 HashMap。它们如下:
//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);
}
Iterator iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry element = (Map.Entry) it.next();
LOGGER.debug("Key: " + element.getKey());
LOGGER.debug("value: " + element.getValue());
}
爪哇 8:
您可以使用 lambda 表达式:
myMap.entrySet().stream().forEach((entry) -> {
Object currentKey = entry.getKey();
Object currentValue = entry.getValue();
});
有关详细信息,请按照此操作。
评论
myMap.forEach( (currentKey,currentValue) -> /* action */ );
我用以下代码将地图的数据复制到另一个地图:
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());
}
它并不能完全回答 OP 的问题,但可能对找到此页面的其他人有用:
如果只需要值而不需要键,则可以执行以下操作:
Map<Ktype, Vtype> myMap = [...];
for (Vtype v: myMap.values()) {
System.out.println("value: " + v);
}
Ktype
,是伪代码。Vtype
这是一个通用的类型安全方法,可以调用它来转储任何给定的 .Map
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);
}
});
}
}
例
以下是其使用示例。请注意,该方法推断出 的类型。Map
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();
}
}
}
输出
One = 0
Two = 1
Three = 3
Object = java.lang.Object@15db9742
Integer = 0
Double = 0.0
我相信这是最简单的方法......
/* 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();
}
如果遍历 的原因在于对值执行操作并写入生成的 。我建议使用 Google Guava 类中的 -methods。Map
Map
transform
Maps
import com.google.common.collect.Maps;
将 添加到导入后,您可以在地图上使用 和,如下所示:Maps
Maps.transformValues
Maps.transformEntries
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);
}
爪哇 8
我们有接受 lambda 表达式的方法。我们也有流 API。考虑一张地图:forEach
Map<String,String> sample = new HashMap<>();
sample.put("A","Apple");
sample.put("B", "Ball");
遍历键:
sample.keySet().forEach((k) -> System.out.println(k));
遍历值:
sample.values().forEach((v) -> System.out.println(v));
遍历条目(使用 forEach 和 Streams):
sample.forEach((k,v) -> System.out.println(k + ":" + v));
sample.entrySet().stream().forEach((entry) -> {
Object currentKey = entry.getKey();
Object currentValue = entry.getValue();
System.out.println(currentKey + ":" + currentValue);
});
流的优点是,如果我们愿意,它们可以很容易地并行化。我们只需要用 in 代替上面的。parallelStream()
stream()
forEachOrdered
与 forEach
有流?不遵循相遇顺序(如果已定义),并且本质上是非确定性的,其中 as 是。所以不保证订单会被保留。另请查看此内容以了解更多信息。forEach
forEachOrdered
forEach
Lambda表达式 Java 8
在 Java 1.8 (Java 8) 中,通过使用 Aggregate 操作(Stream 操作)中的 forEach 方法,这变得容易得多,该方法看起来类似于 Iterable Interface 中的迭代器。
只需将以下语句复制粘贴到您的代码中,并将 HashMap 变量从 hm 重命名为 HashMap 变量即可打印出键值对。
HashMap<Integer,Integer> hm = new HashMap<Integer, Integer>();
/*
* Logic to put the Key,Value pair in your HashMap hm
*/
// Print the key value pair in one line.
hm.forEach((k, v) -> System.out.println("key: " + k + " value:" + v));
// Just copy and paste above line to your code.
下面是我尝试使用 Lambda 表达式的示例代码。这东西太酷了。必须尝试。
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 来实现相同的目的。
Spliterator sit = hm.entrySet().spliterator();
更新
包括指向 Oracle Docs 的文档链接。 有关 Lambda 的更多信息,请转到此链接,并且必须阅读聚合操作,对于 Spliterator,请转到此链接。
如果要按照添加元素的顺序遍历映射,请使用 as 而不是 。LinkedHashMap
Map
这种方法过去对我有用:
LinkedHashMap<String, Integer> test = new LinkedHashMap();
test.put("foo", 69);
test.put("bar", 1337);
for (int i = 0; i < test.size(); i++) {
System.out.println(test.get(test.keySet().toArray()[i]));
}
输出:
69
1337
为了总结其他答案并将它们与我所知道的结合起来,我找到了 10 种主要方法可以做到这一点(见下文)。此外,我还编写了一些性能测试(请参阅下面的结果)。例如,如果我们想找到一个映射的所有键和值的总和,我们可以这样写:
使用迭代器和 Map.Entry
long i = 0; Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator(); while (it.hasNext()) { Map.Entry<Integer, Integer> pair = it.next(); i += pair.getKey() + pair.getValue(); }
使用 foreach 和 Map.Entry
long i = 0; for (Map.Entry<Integer, Integer> pair : map.entrySet()) { i += pair.getKey() + pair.getValue(); }
在 Java 8 中使用 forEach
final long[] i = {0}; map.forEach((k, v) -> i[0] += k + v);
使用 keySet 和 foreach
long i = 0; for (Integer key : map.keySet()) { i += key + map.get(key); }
使用 keySet 和迭代器
long i = 0; Iterator<Integer> itr2 = map.keySet().iterator(); while (itr2.hasNext()) { Integer key = itr2.next(); i += key + map.get(key); }
使用 for 和 Map.Entry
long i = 0; for (Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator(); entries.hasNext(); ) { Map.Entry<Integer, Integer> entry = entries.next(); i += entry.getKey() + entry.getValue(); }
使用 Java 8 Stream API
final long[] i = {0}; map.entrySet().stream().forEach(e -> i[0] += e.getKey() + e.getValue());
并行使用 Java 8 Stream API
final long[] i = {0}; map.entrySet().stream().parallel().forEach(e -> i[0] += e.getKey() + e.getValue());
使用 IterableMap 的
Apache Collections
long i = 0; MapIterator<Integer, Integer> it = iterableMap.mapIterator(); while (it.hasNext()) { i += it.next() + it.getValue(); }
使用 MutableMap of Eclipse (CS) 集合
final long[] i = {0}; mutableMap.forEachKeyValue((key, value) -> { i[0] += key + value; });
性能测试(模式 = AverageTime,系统 = Windows 8.1 64 位,Intel i7-4790 3.60 GHz,16 GB)
对于小地图(100 个元素),得分 0.308 是最好的
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 个元素的地图,得分 37.606 是最好的
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 个元素的地图,得分 1184.767 是最好的
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
图形(性能测试取决于地图大小)
表格(性能测试取决于地图大小)
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 上。
评论
long sum = 0; map.forEach( /* accumulate in variable sum*/);
sum
stream.mapToInt(/*whatever*/).sum
x±e
x-e
x+e
1184.767±332.968
852
1518
1706.676±436.867
1270
2144
3289.866±1445.564
1844
4735
while
for
#8
是一个可怕的例子,因为在添加到 时现在有一个竞争条件。parallel
i
//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 8,您可以使用以下任一方法:
map.forEach((k,v) -> { System.out.println(k + ":" + v); });
艺术
map.entrySet().forEach((e) -> {
System.out.println(e.getKey() + " : " + e.getValue());
});
结果将是相同的(相同的顺序)。由映射支持的 entrySet,因此您获得相同的顺序。第二个很方便,因为它允许您使用 lambda,例如,如果您只想打印大于 5 的 Integer 对象:
map.entrySet()
.stream()
.filter(e-> e.getValue() > 5)
.forEach(System.out::println);
下面的代码显示了通过 LinkedHashMap 和普通 HashMap 进行的迭代(示例)。您将看到顺序的差异:
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("\nLinkedHashMap (2): ");
linkedHashMap.entrySet().forEach((e) -> {
System.out.print(e.getKey() + " : " + e.getValue() + ", ");
});
System.out.println("\n\nHashMap (1): ");
hashMap.forEach((k,v) -> { System.out.print(k + " (#:"+k.hashCode() + "):" + v + ", "); });
System.out.println("\nHashMap (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,
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));
}
}
迭代 Map 非常容易。
for (Object key : map.keySet()) {
Object value = map.get(key);
// Do your stuff
}
例如,你有一个Map<String, int> data;
for (Object key : data.keySet()) {
int value = data.get(key);
}
评论
有很多方法可以做到这一点。以下是几个简单的步骤:
假设你有一张地图,如下所示:
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));
}
使用 Java 8:
map.entrySet().forEach(entry -> System.out.println(entry.getValue()));
Java 8 最紧凑:
map.entrySet().forEach(System.out::println);
在 Java 8 中,您可以使用 forEach 和 lambda 表达式迭代 Map,
map.forEach((k, v) -> System.out.println((k + ":" + v)));
基于 Map 的有效迭代解决方案是从 Java 5 到 Java 7 的循环。在这里:for
for (String key : phnMap.keySet()) {
System.out.println("Key: " + key + " Value: " + phnMap.get(key));
}
从 Java 8 开始,您可以使用 lambda 表达式来遍历 Map。这是一个增强的forEach
phnMap.forEach((k,v) -> System.out.println("Key: " + k + " Value: " + v));
如果你想为 lambda 编写一个条件,你可以这样写:
phnMap.forEach((k,v) -> {
System.out.println("Key: " + k + " Value: " + v);
if ("abc".equals(k)) {
System.out.println("Hello abc");
}
});
我喜欢连接一个计数器,然后保存计数器的最终值;
int counter = 0;
HashMap<String, String> m = new HashMap<String, String>();
for (int i = 0; i < items.length; i++)
{
m.put("firstname" + i, items.get(i).getFirstName());
counter = i;
}
m.put("recordCount", String.valueOf(counter));
然后,当您要检索时:
int recordCount = Integer.parseInf(m.get("recordCount"));
for (int i = 0; i < recordCount; i++)
{
System.out.println("First Name :" + m.get("firstname" + i));
}
使用 Java 7
Map<String,String> sampleMap = new HashMap<>();
for (sampleMap.Entry<String,String> entry : sampleMap.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
/* your Code as per the Business Justification */
}
使用 Java 8
Map<String,String> sampleMap = new HashMap<>();
sampleMap.forEach((k, v) -> System.out.println("Key is : " + k + " Value is : " + v));
如果我有一个在 Java 中实现 Map 接口的对象,并且我希望遍历其中包含的每一对,那么遍历映射的最有效方法是什么?
如果循环键的效率是应用的首要任务,请选择按所需顺序维护键的实现。Map
元素的顺序是否取决于我为接口提供的特定映射实现?
是的,当然可以。
- 有些实现承诺一定的迭代顺序,有些则不然。
Map
- 不同的实现保持键值对的不同顺序。
Map
请参阅我创建的这个表格,其中总结了与 Java 11 捆绑在一起的各种实现。具体而言,请注意迭代顺序列。单击/点击以缩放。Map
您可以看到有四种 Map
实现保持顺序:
TreeMap
ConcurrentSkipListMap
LinkedHashMap
EnumMap
NavigableMap
接口
其中两个实现了 NavigableMap
接口:& 。TreeMap
ConcurrentSkipListMap
较旧的 SortedMap
接口实际上已被较新的 NavigableMap
接口所取代。但您可能会发现第三方实现仅实现了较旧的接口。
自然秩序
如果您想要一个按键的“自然顺序”排列其对的 Map
,请使用 TreeMap
或 ConcurrentSkipListMap
。术语“自然秩序”是指实现可比
的键的类。compareTo
方法返回的值用于排序中的比较。
定制订单
如果要为用于维护排序顺序的键指定自定义排序例程,请传递适合键类的 Comparator
实现。使用 TreeMap
或 ConcurrentSkipListMap
,将 .Comparator
原始广告订单
如果希望地图对保持插入地图时的原始顺序,请使用 LinkedHashMap
。
枚举定义顺序
如果使用枚举(如 DayOfWeek
或 Month
)作为键,请使用 EnumMap
类。该类不仅经过高度优化,使用非常少的内存并且运行速度非常快,而且它按照枚举定义的顺序维护您的对。例如,在迭代时将首先找到 的键,而 的键将是最后一个。DayOfWeek
DayOfWeek.MONDAY
DayOfWeek.SUNDAY
其他注意事项
在选择实现时,还要考虑:Map
- NULL。某些实现禁止/接受 NULL 作为键和/或值。
- 并发。如果要跨线程操作映射,则必须使用支持并发的实现。或者用
Collections::synchronizedMap
包装地图(不太可取)。
这两个注意事项都包含在上图中。
评论
EnumMap
Map.forEach
简单地使用 Map::forEach
将键和值都传递给 BiConsumer
怎么样?
map.forEach((k,v) -> {
System.out.println(k + "->" + v);
});
评论
从 Java 10 开始,您可以使用局部变量推理(又名“var”)来使许多已经可用的答案不那么臃肿。例如:
for (var entry : map.entrySet()) {
System.out.println(entry.getKey() + " : " + entry.getValue());
}
Map<String, String> map =
for (Map.Entry<String, String> entry : map.entrySet()) {
MapKey = entry.getKey()
MapValue = entry.getValue();
}
您可以搜索密钥,在密钥的帮助下,您可以找到映射的关联值,因为映射具有唯一的密钥,请参阅此处或此处复制密钥时会发生什么。
演示地图:
Map<String, String> map = new HashMap();
map.put("name", "Name");
map.put("age", "23");
map.put("address", "NP");
map.put("faculty", "BE");
map.put("major", "CS");
map.put("head", "MDK");
要仅获取密钥,您可以使用如下方法:map.keySet();
for (String key : map.keySet()) {
System.out.println(key);
}
若要仅获取值,可以使用如下方法:map.values();
for (String value : map.values()) {
System.out.println(value);
}
若要同时获取键及其值,您仍然可以使用并获取其相应的值,如下所示:map.keySet();
// this prints the key + value pair
for (String k : map.keySet()) {
System.out.println(k + " " + map.get(k) + " ");
}
map.get(key)
给出该键指向的值。
这些都是迭代 HashMap 的可能方法。
HashMap<Integer,String> map = new HashMap<Integer,String>();
map.put(1, "David"); // Adding elements to Map
map.put(2, "John");
map.put(4, "Samyuktha");
map.put(3, "jasmin");
System.out.println("Iterating Hashmap...");
// way 1 (java 8 Method)
map.forEach((key, value) -> {
System.out.println(key + " : " + value);
});
// way 2 (java 7 Method)
for (Map.Entry me : map.entrySet()) {
System.out.println(me.getKey() + " : " + me.getValue());
}
// way 3 (java 6 Method)
for (Integer key : map.keySet()) {
System.out.println(map.get(key));
}
// way 4 (Legacy way to iterate HashMap)
Iterator iterator = map.entrySet().iterator(); // map.keySet().iterator()
while (iterator.hasNext())
{
Map.Entry me = (Map.Entry)iterator.next();
System.out.println(me.getKey() + " : " + me.getValue());
}
}
评论