Java 实例 – 遍历 HashTable 的键值(快速上手)

Java 实例 – 遍历 HashTable 的键值

在 Java 开发中,Map 接口是处理键值对数据的核心工具。而 HashTable 作为早期的哈希表实现,虽然在现代开发中逐渐被 HashMap 取代,但它依然具有学习价值,尤其在理解线程安全、同步机制等方面。今天我们要深入探讨一个非常实用的场景:Java 实例 – 遍历 HashTable 的键值。这个操作在处理配置信息、缓存数据、统计分析等场景中极为常见。

想象一下,你有一个存放用户信息的 HashTable,键是用户名,值是用户等级。当你需要给所有用户发一封通知邮件时,就必须遍历所有键值对,获取用户名和等级信息。这个过程,就是我们今天要掌握的核心技能。


什么是 HashTable?

HashTable 是 Java 集合框架中的一个类,实现了 Map 接口,用于存储键值对(key-value pairs)。它通过哈希算法将键映射到数组中的特定位置,从而实现快速查找。

与 HashMap 不同,HashTable 是线程安全的,所有关键方法都使用 synchronized 关键字进行同步。这意味着在多线程环境下,多个线程可以安全地访问同一个 HashTable 实例,而不会出现数据不一致的问题。但这也带来了一个代价:性能相对较低,尤其在高并发场景下。

💡 小贴士:HashTable 与 HashMap 最大的区别在于,HashTable 不允许键或值为 null,而 HashMap 允许。


遍历 HashTable 的 4 种常见方式

在实际开发中,遍历 HashTable 有多种方法。每种方法都有其适用场景和性能特点。下面我们逐一讲解,结合代码实例,帮助你快速掌握。

使用 keySet() 遍历键,再通过 get() 获取值

这是最直观、最容易理解的方式。先获取所有键的集合,然后遍历这些键,再通过键去取对应的值。

import java.util.Hashtable;

public class HashTableTraversalExample {
    public static void main(String[] args) {
        // 创建一个 HashTable 并添加数据
        Hashtable<String, Integer> scores = new Hashtable<>();
        scores.put("张三", 85);
        scores.put("李四", 92);
        scores.put("王五", 78);
        scores.put("赵六", 96);

        // 第一步:获取所有键的集合
        // keySet() 返回一个 Set,包含 HashTable 中所有的键
        for (String name : scores.keySet()) {
            // 第二步:通过键获取对应的值
            Integer score = scores.get(name);
            // 输出结果
            System.out.println("用户: " + name + ", 分数: " + score);
        }
    }
}

✅ 优点:代码简洁,逻辑清晰,适合初学者。
⚠️ 缺点:每次遍历都需要调用 get() 方法,会增加一次哈希计算,性能略低。


使用 entrySet() 遍历键值对(推荐方式)

这是最高效、最推荐的方式。entrySet() 返回一个 Set<Map.Entry<K, V>>,每个 Entry 都包含一个键和一个值。直接通过 Entry 获取键和值,避免了重复的 get() 操作。

import java.util.Hashtable;
import java.util.Map;

public class HashTableEntrySetExample {
    public static void main(String[] args) {
        // 创建 HashTable 并添加数据
        Hashtable<String, Integer> scores = new Hashtable<>();
        scores.put("张三", 85);
        scores.put("李四", 92);
        scores.put("王五", 78);
        scores.put("赵六", 96);

        // 使用 entrySet() 获取所有键值对
        // entrySet() 返回一个 Set,其中每个元素是 Map.Entry 类型
        for (Map.Entry<String, Integer> entry : scores.entrySet()) {
            // 通过 getKey() 获取键,getValue() 获取值
            String name = entry.getKey();
            Integer score = entry.getValue();
            // 输出结果
            System.out.println("用户: " + name + ", 分数: " + score);
        }
    }
}

✅ 优点:只遍历一次,无需重复 get(),性能最佳。
✅ 推荐在大多数场景下使用此方式。


使用 Iterator 遍历(适用于复杂控制场景)

当你需要在遍历过程中删除元素,或进行复杂的条件判断时,推荐使用 Iterator。它提供了更灵活的控制能力。

import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;

public class HashTableIteratorExample {
    public static void main(String[] args) {
        // 创建 HashTable 并添加数据
        Hashtable<String, Integer> scores = new Hashtable<>();
        scores.put("张三", 85);
        scores.put("李四", 92);
        scores.put("王五", 78);
        scores.put("赵六", 96);

        // 获取 entrySet 的迭代器
        Iterator<Map.Entry<String, Integer>> iterator = scores.entrySet().iterator();

        // 使用 while 循环遍历
        while (iterator.hasNext()) {
            Map.Entry<String, Integer> entry = iterator.next();
            String name = entry.getKey();
            Integer score = entry.getValue();

            // 可以在此处添加条件判断,比如删除分数低于 80 的用户
            if (score < 80) {
                iterator.remove(); // 安全删除当前元素
                System.out.println("已删除用户: " + name + ",分数: " + score);
            } else {
                System.out.println("用户: " + name + ", 分数: " + score);
            }
        }
    }
}

✅ 优点:支持在遍历中安全删除元素,避免 ConcurrentModificationException。
⚠️ 语法稍复杂,适合有经验的开发者。


使用 Java 8 的 forEach 方法(函数式编程风格)

Java 8 引入了 Lambda 表达式和 forEach 方法,让代码更简洁,也更符合现代编程趋势。

import java.util.Hashtable;

public class HashTableForEachExample {
    public static void main(String[] args) {
        // 创建 HashTable 并添加数据
        Hashtable<String, Integer> scores = new Hashtable<>();
        scores.put("张三", 85);
        scores.put("李四", 92);
        scores.put("王五", 78);
        scores.put("赵六", 96);

        // 使用 forEach 方法,参数是 Lambda 表达式
        // (key, value) -> System.out.println(...) 表示接收两个参数:key 和 value
        scores.forEach((name, score) -> {
            System.out.println("用户: " + name + ", 分数: " + score);
        });
    }
}

✅ 优点:代码最简洁,语法优雅,适合函数式编程爱好者。
⚠️ 需要 Java 8 或更高版本支持。


不同遍历方式对比表

方法 性能 可读性 是否支持删除 适用场景
keySet() + get() 中等 不支持 初学者入门,逻辑简单
entrySet() + for-each 支持(需用 Iterator) 通用推荐,性能最优
Iterator 遍历 支持 需要删除或复杂控制
forEach + Lambda 不支持(需手动控制) 现代 Java 项目,代码简洁

实际应用案例:统计学生成绩

我们来模拟一个真实场景:学校需要统计全班学生的平均分、最高分和最低分。使用 HashTable 存储数据,再遍历计算。

import java.util.Hashtable;

public class StudentScoreAnalysis {
    public static void main(String[] args) {
        // 存储学生姓名和分数
        Hashtable<String, Integer> scores = new Hashtable<>();
        scores.put("张三", 85);
        scores.put("李四", 92);
        scores.put("王五", 78);
        scores.put("赵六", 96);
        scores.put("钱七", 88);

        int total = 0;
        int maxScore = Integer.MIN_VALUE;
        int minScore = Integer.MAX_VALUE;

        // 使用 entrySet 遍历所有键值对
        for (var entry : scores.entrySet()) {
            int score = entry.getValue();
            total += score;
            if (score > maxScore) maxScore = score;
            if (score < minScore) minScore = score;
        }

        double average = (double) total / scores.size();

        // 输出分析结果
        System.out.println("总人数: " + scores.size());
        System.out.println("总分: " + total);
        System.out.println("平均分: " + String.format("%.2f", average));
        System.out.println("最高分: " + maxScore);
        System.out.println("最低分: " + minScore);
    }
}

运行结果:

总人数: 5
总分: 439
平均分: 87.80
最高分: 96
最低分: 78

这个例子展示了 Java 实例 – 遍历 HashTable 的键值 在实际业务中的强大作用。


常见问题与注意事项

  1. HashTable 不允许 null 键或值
    如果你尝试插入 scores.put(null, 80),会抛出 NullPointerException

  2. 遍历时不要修改集合结构
    如果在 for-each 循环中直接调用 scores.remove("张三"),会抛出 ConcurrentModificationException。必须使用 Iterator 的 remove 方法。

  3. 性能建议
    优先使用 entrySet() 遍历,避免多次调用 get()

  4. 线程安全 ≠ 万能
    虽然 HashTable 是线程安全的,但如果你需要更高的并发性能,建议使用 ConcurrentHashMap


总结

今天我们深入学习了 Java 实例 – 遍历 HashTable 的键值 的多种方式。从最基础的 keySet(),到推荐的 entrySet(),再到 Iterator 和 Lambda 表达式,每种方式都有其适用场景。

  • 初学者建议从 keySet() 开始,理解逻辑。
  • 实际项目中,应优先使用 entrySet(),兼顾性能与可读性。
  • 需要删除元素时,使用 Iterator。
  • 追求代码简洁时,可使用 Java 8 的 forEach。

掌握这些技巧,你不仅能高效处理键值对数据,还能为后续学习 ConcurrentHashMap、Stream API 打下坚实基础。记住:代码不仅是功能的实现,更是思维的表达。