Hashtable 是一个遗留类(Legacy Class),存在于 Java 的 java.util 包中,它和 HashMap 非常相似,都是键值对(Key-Value)集合,但有一个关键区别:Hashtable 是线程安全的(synchronized),而 HashMap 不是,这意味着在多线程环境下,可以直接使用 Hashtable 而不需要额外的同步措施。

由于 Hashtable 实现了 Map 接口,因此遍历它的方法与遍历 HashMap 或其他 Map 实现类的方法基本相同,下面我们介绍几种最常用和最推荐的遍历方式。
准备工作:创建一个 Hashtable 示例
在开始遍历之前,我们先创建一个 Hashtable 实例并填充一些数据,以便后续的代码演示。
import java.util.Hashtable;
import java.util.Map;
public class HashtableTraversalExample {
public static void main(String[] args) {
// 1. 创建一个 Hashtable 实例
// 注意:Hashtable 的构造函数可以指定初始容量和加载因子
Hashtable<String, Integer> scores = new Hashtable<>();
// 2. 向 Hashtable 中添加元素
scores.put("Alice", 95);
scores.put("Bob", 88);
scores.put("Charlie", 76);
scores.put("David", 92);
System.out.println("原始的 Hashtable: " + scores);
}
}
使用 entrySet() 和 for-each 循环(推荐)
这是最常用、最推荐的方法,它通过 Map.Entry 对象来同时获取键和值,代码简洁高效。
原理:
Map.entrySet() 方法返回一个 Set 集合,该集合包含了 Map 中所有的键值对,每个键值对都被封装在一个 Map.Entry 对象中,我们可以直接遍历这个 Set。

代码示例:
System.out.println("\n--- 方法一:使用 entrySet() 和 for-each 循环 ---");
for (Map.Entry<String, Integer> entry : scores.entrySet()) {
// entry.getKey() 获取键
// entry.getValue() 获取值
String name = entry.getKey();
int score = entry.getValue();
System.out.println("姓名: " + name + ", 分数: " + score);
}
优点:
- 代码简洁:使用 for-each 循环,代码可读性高。
- 性能高:这是遍历
Map最高效的方式之一,因为它直接操作内部的Entry对象,避免了多次查找。
使用 keySet() 和 for-each 循环
如果你只需要遍历所有的键,或者需要先获取键再通过键去获取值,可以使用 keySet()。
原理:
Map.keySet() 方法返回一个包含 Map 中所有键的 Set 集合,遍历这个键集合,然后通过 Map.get(key) 方法来获取对应的值。

代码示例:
System.out.println("\n--- 方法二:使用 keySet() 和 for-each 循环 ---");
for (String name : scores.keySet()) {
// scores.get(name) 通过键获取值
int score = scores.get(name);
System.out.println("姓名: " + name + ", 分数: " + score);
}
优点:
- 当你只需要键时,非常直接。
- 代码同样简洁。
缺点:
- 性能稍差:对于
Map中的每一个键,scores.get(name)方法都需要执行一次查找操作。Map很大,这会比entrySet()方法慢。
使用 values() 和 for-each 循环
如果你只关心值,而不关心键,可以使用 values() 方法。
原理:
Map.values() 方法返回一个包含 Map 中所有值的 Collection 集合,你可以直接遍历这个值的集合。
代码示例:
System.out.println("\n--- 方法三:使用 values() 和 for-each 循环 ---");
for (Integer score : scores.values()) {
System.out.println("分数: " + score);
}
优点:
- 当你只需要值时,非常方便。
缺点:
- 无法在遍历过程中直接获取到对应的键。
使用迭代器(Iterator)
虽然 for-each 循环是主流,但在某些情况下(例如需要在遍历时删除元素),使用传统的 Iterator 是更安全的选择。Hashtable 的所有集合视图(entrySet(), keySet(), values())都返回的集合都是“快速失败”(fail-fast)的,这意味着如果在迭代过程中,除了 iterator.remove() 之外的任何方式修改了 Map,都会抛出 ConcurrentModificationException 异常。
代码示例:
System.out.println("\n--- 方法四:使用 Iterator ---");
// 1. 使用 entrySet() 获取迭代器
System.out.println("--- 遍历 entrySet ---");
Iterator<Map.Entry<String, Integer>> entryIterator = scores.entrySet().iterator();
while (entryIterator.hasNext()) {
Map.Entry<String, Integer> entry = entryIterator.next();
System.out.println("姓名: " + entry.getKey() + ", 分数: " + entry.getValue());
}
// 2. 使用 keySet() 获取迭代器
System.out.println("\n--- 遍历 keySet ---");
Iterator<String> keyIterator = scores.keySet().iterator();
while (keyIterator.hasNext()) {
String name = keyIterator.next();
System.out.println("姓名: " + name + ", 分数: " + scores.get(name));
}
关于在遍历时删除元素:
如果你想删除一个元素,必须使用迭代器的 remove() 方法。
System.out.println("\n--- 使用 Iterator 安全删除元素 ---");
Iterator<Map.Entry<String, Integer> > iterator = scores.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, Integer> entry = iterator.next();
// 假设我们要删除分数低于 80 的学生
if (entry.getValue() < 80) {
iterator.remove(); // 正确的删除方式
}
}
System.out.println("删除后的 Hashtable: " + scores);
使用 Java 8 的 forEach 和 Lambda 表达式
如果你使用的是 Java 8 或更高版本,可以利用 Lambda 表达式和 Map 接口的 forEach 方法,以函数式的方式遍历 Map,代码非常优雅。
代码示例:
System.out.println("\n--- 方法五:使用 Java 8 forEach ---");
scores.forEach((name, score) -> {
System.out.println("姓名: " + name + ", 分数: " + score);
});
优点:
- 极其简洁:一行代码即可完成遍历。
- 函数式编程风格:代码更具表现力。
总结与对比
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
entrySet() + for-each |
需要同时访问键和值 | 性能最高,代码简洁 | - |
keySet() + for-each |
只需要键,或者需要根据键获取值 | 代码简洁 | 性能稍差(多次查找) |
values() + for-each |
只需要值 | 代码简洁 | 无法获取键 |
Iterator |
需要在遍历过程中安全地删除元素 | 安全,支持删除操作 | 代码比 for-each 稍显冗长 |
forEach (Java 8+) |
现代 Java 开发,追求简洁优雅 | 代码最简洁,函数式风格 | 需要 Java 8+ 环境 |
最佳实践建议:
- 如果你需要同时访问键和值,强烈推荐使用
entrySet()和 for-each 循环,这是性能和可读性之间的最佳平衡点。 - 如果你使用的是 Java 8 或更高版本,并且喜欢函数式编程风格,
map.forEach()是一个非常棒的选择。 - 如果你需要在遍历过程中删除元素,请务必使用
Iterator的remove()方法。
