您的位置:

Java Map循环指南

一、遍历Map的三种方法

Java中的Map是一种以键值对形式存储数据的容器,常用的实现类有HashMap、LinkedHashMap和TreeMap。遍历Map是我们在使用Map时最常遇到的问题之一,下面介绍三种常用的遍历方法。

1. 通过entrySet遍历

Map map = new HashMap<>();
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");

for (Map.Entry
    entry : map.entrySet()) {
    System.out.println(entry.getKey() + " " + entry.getValue());
}

   
  

使用entrySet遍历时,先获取到Map的所有entry集合,然后遍历所有entry,通过entry的getKey和getValue方法获取键值对。

2. 通过keySet遍历

Map map = new HashMap<>();
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");

for (Integer key : map.keySet()) {
    System.out.print(key + " ");
    System.out.println(map.get(key));
}

  

使用keySet遍历时,先获取到Map的所有key集合,然后遍历所有key,通过Map的get方法获取对应的值。

3. 通过values遍历

Map map = new HashMap<>();
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");

for (String value : map.values()) {
    System.out.println(value);
}

  

使用values遍历时,直接获取到Map的所有值的集合,然后遍历所有值。

二、如何遍历有序Map

有序Map是指像LinkedHashMap和TreeMap这样的实现类,能够按照某种顺序(通常是插入顺序或按照键的自然顺序)存储键值对。如何遍历这些有序Map呢?

其实原理和遍历HashMap一样,只是在创建实例时需要指定排序的方式。

1. LinkedHashMap

Map map = new LinkedHashMap<>(16, 0.75f, true);
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");

for (Map.Entry
    entry : map.entrySet()) {
    System.out.println(entry.getKey() + " " + entry.getValue());
}

   
  

在创建LinkedHashMap时,需要传入三个参数:initialCapacity(初始化容量)、loadFactor(负载因子)和accessOrder(排序方式)。accessOrder为true时表示按照访问顺序排序,为false时表示按照插入顺序排序。

2. TreeMap

Map map = new TreeMap<>();
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");

for (Map.Entry
    entry : map.entrySet()) {
    System.out.println(entry.getKey() + " " + entry.getValue());
}

   
  

在创建TreeMap时,只需要像创建普通HashMap一样传入默认的初始化容量即可。

三、遍历Map的性能比较

不同的遍历方式对Map的性能有影响,下面通过实验来看看它们之间的性能差异。

实验代码如下:

Map map = new HashMap<>();
Random random = new Random();
for (int i = 0; i < 1000000; i++) {
    map.put(random.nextInt(1000000), "some value");
}

long start = System.currentTimeMillis();
for (Map.Entry
    entry : map.entrySet()) {
    // do nothing
}
long end = System.currentTimeMillis();
System.out.println("遍历entrySet耗时:" + (end - start) + "ms");

start = System.currentTimeMillis();
for (Integer key : map.keySet()) {
    // do nothing
}
end = System.currentTimeMillis();
System.out.println("遍历keySet耗时:" + (end - start) + "ms");

start = System.currentTimeMillis();
for (String value : map.values()) {
    // do nothing
}
end = System.currentTimeMillis();
System.out.println("遍历values耗时:" + (end - start) + "ms");

   
  

实验结果(遍历1000000个元素,单位:毫秒):

遍历entrySet耗时:14ms

遍历keySet耗时:16ms

遍历values耗时:33ms

从实验结果来看,通过entrySet遍历Map是最快的,而通过values遍历是最慢的。

四、如何在多线程环境下遍历Map

在多线程环境下使用Map时,遍历是一个非常常见的操作,但是需要注意线程安全问题。

如果只是读取操作,可以直接使用Java 8中的forEach方法,示例代码如下:

Map map = new ConcurrentHashMap<>();
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");

map.forEach((key, value) -> {
    System.out.println(key + " " + value);
});

  

如果同时存在读取和写入操作,可以使用并发安全的遍历方式,如下代码所示:

Map map = new ConcurrentHashMap<>();
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");

map.entrySet().parallelStream().forEach(entry -> {
    System.out.println(entry.getKey() + " " + entry.getValue());
});

  

使用parallelStream遍历Map时,底层会自动实现并发安全,处理速度也会更快。