【Java基础】Java集合Map遇到的坑

Java 集合框架中的 Map 是一种非常常用的数据结构,它可以将 key 和 value 进行映射,提供了丰富的操作方法和函数。然而,在使用 Map 的过程中,我们也会遇到各种问题和坑,本文就为大家介绍 Java集合Map遇到的坑及解决方法。


1. 空指针异常

在使用 Map 的过程中,最容易出现的问题就是空指针异常。这通常发生在我们没有初始化或者清空 Map 的情况下进行操作。例如:

Map<String, Integer> map = null;
map.put("a", 1); // 报错:NullPointerException

在这个例子中,因为我们没有给 map 分配内存空间,所以调用 put 方法时会报空指针异常。要解决这个问题,我们需要在使用 Map 前先进行初始化,如下:

Map<String, Integer> map = new HashMap<>();
map.put("a", 1);

2. Key 重复问题

Map 的特性是 key-value 映射,对于不同的 key,对应的 value 可以是不同的。但是当我们向一个已经存在的 key 中插入新值时,会出现覆盖的情况。例如:

Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("a", 2);
System.out.println(map.get("a")); // 输出 2

 在这个例子中,我们先将一个 key 为 "a" 的值设置为 1,然后再将其设置为 2。由于 key 值的重复,第二次 put 操作将会覆盖掉原来的值,最终输出结果为 2。要避免这个问题,我们可以使用 containsKey 方法或者 getOrDefault 方法来判断 key 是否存在,如下:

Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
if (!map.containsKey("a")) { // 如果 key 不存在就添加
    map.put("a", 2);
}
System.out.println(map.get("a")); // 输出 1

3. 迭代器并发修改

当我们使用 Map 的迭代器时,如果在迭代过程中对 Map 进行了修改,则会报出 ConcurrentModificationException 异常。例如:

Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
for (String key : map.keySet()) {
    if (key.equals("a")) {
        map.remove(key); // 报错:ConcurrentModificationException
    }
}

在这个例子中,我们在遍历 keySet 的同时删除了 Map 中的元素,导致了 ConcurrentModificationException 异常。解决这个问题的方法是使用迭代器的 remove 方法进行操作,如下:

Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
Iterator<Map.Entry<String, Integer>> iter = map.entrySet().iterator();
while (iter.hasNext()) {
    Map.Entry<String, Integer> entry = iter.next();
    if (entry.getKey().equals("a")) {
        iter.remove();
    }
}

在这个例子中,我们使用了 entrySet 方法获取到 Map 中的每一个键值对,然后使用迭代器进行操作。当需要删除元素时,使用迭代器的 remove 方法可以避免并发修改问题。

4. Hash 冲突

Map 的底层是通过哈希表实现的,而哈希表本身就存在哈希冲突的问题。当两个不同的 key 值计算得出的 hash 值相同,就会产生哈希冲突。这种情况下,如果我们没有正确处理,就有可能导致数据无法正常存储和访问。例如:

class Key {
    private final int value;

    public Key(int value) {
        this.value = value;
    }

    @Override
    public int hashCode() {
        return 1;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Key) {
            Key other = (Key) obj;
            return this.value == other.value;
        }
        return false;
    }
}


Map<Key, String> map = new HashMap<>();
map.put(new Key(1), "a");
map.put(new Key(2), "b");
System.out.println(map.get(new Key(1))); // 输出 null

在这个例子中,由于我们重写了 Key 类的 hashCode 方法,将其返回值设为了 1,所以不同的 Key 对象计算得到的 hash 值都是相同的。当我们使用一个新的 Key(1) 对象来访问 Map 时,实际上它的 hashCode 和之前添加到 Map 中的 Key(1) 对象是不同的,因此无法正常获取到对应的 value 值。 要解决这个问题,我们需要确保对于相同的 key,它们计算得到的 hash 值是一样的,并且重写 equals 方法,比较两个对象是否相等。例如:

class Key {
    private final int value;

    public Key(int value) {
        this.value = value;
    }

    @Override
    public int hashCode() {
        return Objects.hash(value);
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Key) {
            Key other = (Key) obj;
            return this.value == other.value;
        }
        return false;
    }
}

Map<Key, String> map = new HashMap<>();
map.put(new Key(1), "a");
map.put(new Key(2), "b");
System.out.println(map.get(new Key(1))); // 输出 a

在这个例子中,我们使用了 Objects.hash 方法来计算哈希值,并重写了 equals 方法,确保相同的 key 值可以被正确访问。

5. 总结

在使用 Java 集合框架中的 Map 时,我们需要注意空指针异常、Key 的重复问题、迭代器并发修改、Hash 冲突等坑点。通过适当地初始化 Map、正确处理 key-value 映射关系、使用正确的遍历方式,以及重写 hashCode 和 equals 等方法,我们可以避免这些问题,使得 Map 在程序中正常运行并发挥作用。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Java中的数组和集合是用来存储和操作数据的常用数据结构。数组是一种固定大小的数据结构,用于存储同一类型的元素。数组声明时需要指定元素的类型,并且大小是固定的,不能动态改变。而集合是一种动态大小的数据结构,可以根据需要动态改变大小。集合以object形式来存储元素,因此可以存储不同类型的元素。 在Java中,集合分为List、Set和Map三种主要类型。List是一种有序的集合,可以存储重复的元素。常见的List实现类有ArrayList、LinkedList和Vector。Set是一种不允许重复元素的集合,常见的Set实现类有HashSet和TreeSet。Map是一种键值对的集合,每个元素都包含一个键和一个值,键是唯一的。常见的Map实现类有HashMap、HashTable和TreeMap。 数组和集合在功能上有一些区别。数组声明时需要指定元素的类型,而集合不需要。数组的大小是固定的,而集合可以动态改变大小。此外,数组是一种可读/可写的数据结构,而集合可以提供只读版本。 总结来说,数组和集合都是用来存储和操作数据的数据结构,但数组是固定大小的,集合是动态大小的。数组声明时需要指定元素的类型,而集合不需要。数组比集合更快,但集合提供了更多的功能。在Java中,集合分为List、Set和Map三种主要类型,每种类型都有不同的实现类。 #### 引用[.reference_title] - *1* *3* [Java之数组array和集合list、set、map](https://blog.csdn.net/diaolapei9880/article/details/102382030)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Java必要准确区别之数组Array和集合list、map、set](https://blog.csdn.net/jagel_95/article/details/83112811)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宝爷~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值