Java Map集合:你的数据查找神器

34 阅读4分钟

Java Map集合:你的数据查找神器

各位道友们好,我是会编程的吕洞宾!今天咱们来聊聊Java中的Map集合——这玩意儿就像是数据界的"电话本",通过键(key)快速找到对应的值(value),让你的查找操作快到飞起!

什么是Map?

想象一下天庭的仙人通讯录:通过仙人的名字(键)就能快速找到他的仙府地址(值)。Map就是这样一种键值对(key-value)的存储结构,每个键都是唯一的,就像每个仙人都有独一无二的名字一样。

三大查找高手

1. HashMap - 闪电查找王

HashMap就像是个拥有超快查找能力的千里眼:

Map<String, String> immortalMap = new HashMap<>();
immortalMap.put("吕洞宾", "纯阳宫");
immortalMap.put("何仙姑", "莲花池");
immortalMap.put("铁拐李", "葫芦山");

// 通过名字快速找到仙府!
System.out.println(immortalMap.get("吕洞宾")); // 输出:纯阳宫

特点

  • 基于哈希表,查找速度O(1)
  • 不保证顺序(仙人们随意站队)
  • 允许一个null键和多个null值

2. TreeMap - 自动排序大师

TreeMap就像是个自动按字母排序的纪律委员:

Map<String, String> sortedImmortalMap = new TreeMap<>();
sortedImmortalMap.put("钟离权", "终南山");
sortedImmortalMap.put("蓝采和", "花篮洞");
sortedImmortalMap.put("吕洞宾", "纯阳宫");

// 自动按键的字典序排序!
for (String name : sortedImmortalMap.keySet()) {
    System.out.println(name + " -> " + sortedImmortalMap.get(name));
}
// 输出顺序:蓝采和、吕洞宾、钟离权

特点

  • 基于红黑树,按键自动排序
  • 查找速度O(log n)
  • 不允许null键

3. LinkedHashMap - 有序记录员

LinkedHashMap就像是既保持插入顺序又快速查找的完美主义者:

Map<String, String> orderedImmortalMap = new LinkedHashMap<>();
orderedImmortalMap.put("吕洞宾", "纯阳宫");
orderedImmortalMap.put("何仙姑", "莲花池");
orderedImmortalMap.put("铁拐李", "葫芦山");

// 保持插入顺序!
for (String name : orderedImmortalMap.keySet()) {
    System.out.println(name); // 输出顺序和插入顺序一致
}

特点

  • 保持键的插入顺序
  • 查找性能接近HashMap
  • 适合需要记录访问顺序的场景

Map的仙法秘籍

基本操作演示

Map<String, Integer> immortalAges = new HashMap<>();

// 添加键值对
immortalAges.put("吕洞宾", 1000);
immortalAges.put("何仙姑", 800);
immortalAges.put("铁拐李", 1200);

// 获取值
System.out.println("吕洞宾年龄:" + immortalAges.get("吕洞宾"));

// 检查键是否存在
System.out.println("有钟离权吗?" + immortalAges.containsKey("钟离权"));

// 检查值是否存在
System.out.println("有800岁的仙人吗?" + immortalAges.containsValue(800));

// 修改值
immortalAges.put("吕洞宾", 1001); // 吕洞宾又长一岁!

// 删除键值对
immortalAges.remove("铁拐李");

// 获取大小
System.out.println("记录数量:" + immortalAges.size());

// 清空Map
immortalAges.clear();

遍历的三种仙术

方法一:遍历所有键

for (String name : immortalAges.keySet()) {
    System.out.println(name + " 年龄:" + immortalAges.get(name));
}

方法二:遍历所有值

for (Integer age : immortalAges.values()) {
    System.out.println("有仙人年龄:" + age);
}

方法三:遍历键值对(推荐)

for (Map.Entry<String, Integer> entry : immortalAges.entrySet()) {
    System.out.println(entry.getKey() + " -> " + entry.getValue());
}

实用技巧大放送

1. 获取或默认值

// 如果键不存在,返回默认值
int age = immortalAges.getOrDefault("钟离权", 500);
System.out.println("钟离权年龄:" + age); // 输出:500

2. 不存在时才添加

// 只有键不存在时才添加
immortalAges.putIfAbsent("曹国舅", 600);

3. 合并操作

Map<String, Integer> newAges = new HashMap<>();
newAges.put("韩湘子", 700);
newAges.put("曹国舅", 600);

// 合并两个Map
immortalAges.putAll(newAges);

4. Java 8+ 新特性

// 如果键存在,更新值
immortalAges.computeIfPresent("吕洞宾", (key, oldValue) -> oldValue + 1);

// 如果键不存在,计算新值
immortalAges.computeIfAbsent("张果老", key -> 900);

// 遍历并处理
immortalAges.forEach((name, age) -> 
    System.out.println(name + "已经" + age + "岁了")
);

实战应用场景

场景1:单词统计

// 统计文章中每个单词出现的次数
String text = "java map java collection map set";
Map<String, Integer> wordCount = new HashMap<>();

for (String word : text.split(" ")) {
    wordCount.put(word, wordCount.getOrDefault(word, 0) + 1);
}

System.out.println(wordCount); // 输出:{java=2, collection=1, set=1, map=2}

场景2:缓存系统

// 简单的缓存实现
Map<String, Object> cache = new HashMap<>();

public Object getFromCache(String key) {
    return cache.get(key);
}

public void putToCache(String key, Object value) {
    cache.put(key, value);
}

场景3:配置管理

// 应用配置管理
Map<String, String> config = new LinkedHashMap<>();
config.put("database.url", "jdbc:mysql://localhost:3306/test");
config.put("database.username", "root");
config.put("database.password", "password");

// 保持插入顺序,便于阅读和管理

性能对比表

操作HashMapTreeMapLinkedHashMap
添加元素⚡️ 超快🐢 较慢(要排序)⚡️ 快
查找元素⚡️ 超快🐢 较快⚡️ 超快
删除元素⚡️ 超快🐢 较慢⚡️ 快
保持顺序❌ 不保证✅ 按键排序✅ 插入顺序

避坑指南

自定义对象作为键

如果使用自定义对象作为键,必须重写equals()和hashCode()方法:

class Immortal {
    private String name;
    private String palace;
    
    public Immortal(String name, String palace) {
        this.name = name;
        this.palace = palace;
    }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Immortal immortal = (Immortal) o;
        return Objects.equals(name, immortal.name);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(name);
    }
}

// 现在可以正确作为键使用了
Map<Immortal, String> immortalDetails = new HashMap<>();
immortalDetails.put(new Immortal("吕洞宾", "纯阳宫"), "八仙之首");

并发安全问题

HashMap不是线程安全的,多线程环境下需要使用ConcurrentHashMap:

Map<String, String> concurrentMap = new ConcurrentHashMap<>();
// 现在可以在多线程环境下安全使用了

选择口诀

  • 要最快查找:用HashMap
  • 要自动排序:用TreeMap
  • 要保持插入顺序:用LinkedHashMap
  • 要线程安全:用ConcurrentHashMap
  • 自定义对象作为键:记得重写equals和hashCode!

总结

Map就像是Java世界的"查找大师":

  • HashMap:闪电查找,适合大多数场景
  • TreeMap:自动排序,需要有序时使用
  • LinkedHashMap:保持顺序,需要记录插入顺序时使用

记住:Map的核心使命就是快速查找!当你需要通过键快速找到对应值时,请毫不犹豫地请出Map大法!