说到HashMap我们再熟悉不过了,写代码的时候几乎天天用。今天就把HashMap中的方法撸一撸,看看还有哪些好用又被我们遗漏的方法。
一、HashMap常用方法
在 HashMap 中,常用的一些方法包括插入、删除、查找等操作。下面通过具体的代码示例来说明这些方法的使用:
import java.util.HashMap;
public class HashMapExample {
public static void main(String[] args) {
// 创建一个 HashMap
HashMap<String, Integer> map = new HashMap<>();
// 1. put() - 插入元素
map.put("apple", 1);
map.put("banana", 2);
map.put("cherry", 3);
System.out.println("After put: " + map);
// 2. get() - 根据 key 查找元素
int value = map.get("apple");
System.out.println("Value for key 'apple': " + value);
// 3. containsKey() - 检查 key 是否存在
boolean hasKey = map.containsKey("banana");
System.out.println("Contains key 'banana': " + hasKey);
// 4. containsValue() - 检查 value 是否存在
boolean hasValue = map.containsValue(3);
System.out.println("Contains value 3: " + hasValue);
// 5. remove() - 删除 key-value 对
map.remove("cherry");
System.out.println("After remove 'cherry': " + map);
// 6. size() - 获取 HashMap 的大小
int size = map.size();
System.out.println("Size of the map: " + size);
// 7. isEmpty() - 检查 HashMap 是否为空
boolean isEmpty = map.isEmpty();
System.out.println("Is the map empty? " + isEmpty);
// 8. keySet() - 获取所有的 key
System.out.println("All keys: " + map.keySet());
// 9. values() - 获取所有的 value
System.out.println("All values: " + map.values());
// 10. entrySet() - 获取所有的键值对
System.out.println("All entries: " + map.entrySet());
// 11. clear() - 清空 HashMap
map.clear();
System.out.println("After clear: " + map);
}
}
详细说明:
put(K key, V value):插入一个键值对到 HashMap 中。如果键已经存在,则更新其对应的值。
get(Object key):根据给定的键返回对应的值。如果键不存在,返回 null。
containsKey(Object key):判断 HashMap 中是否包含指定的键。
containsValue(Object value):判断 HashMap 中是否包含指定的值。
remove(Object key):根据键移除相应的键值对。
size():返回 HashMap 中的键值对数量。
isEmpty():判断 HashMap 是否为空。
keySet():返回所有键的集合(Set 类型)。
values():返回所有值的集合(Collection 类型)。
entrySet():返回所有键值对的集合(Set<Map.Entry<K, V>> 类型)。
clear():清空 HashMap 中的所有键值对。
这些方法我们闭着眼睛都能写出来,但还有一些好用又没有被我们发现的方法。
二、HashMap常常被忽视的好方法
putIfAbsent(K key, V value):
作用:如果指定的键还没有对应的值,那么将键值对插入到 HashMap 中。如果键已经存在,不会进行覆盖操作。
示例:
map.putIfAbsent("apple", 10); // 如果 "apple" 存在,则不更新
System.out.println("After putIfAbsent: " + map);
replace(K key, V value):
作用:替换指定键的值,如果键存在的话。与 put 不同的是,replace 不会在键不存在时插入新值。
示例:
map.replace("banana", 20); // 如果 "banana" 存在,替换其值
System.out.println("After replace: " + map);
replace(K key, V oldValue, V newValue):
作用:当且仅当键存在且其当前值等于 oldValue 时,才会替换为 newValue。
示例:
map.replace("banana", 2, 20); // 如果 "banana" 的值是 2,则替换为 20
System.out.println("After conditional replace: " + map);
getOrDefault(Object key, V defaultValue):
作用:返回与指定键关联的值;如果键不存在,则返回默认值 defaultValue。
示例:
int value = map.getOrDefault("orange", 0); // 如果 "orange" 不存在,返回 0
System.out.println("Value for key 'orange' (or default): " + value);
merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction):
作用:将键和值合并。如果键不存在,将该键和值插入。如果键存在,将现有值与新值使用 remappingFunction 合并。
示例:
map.merge("apple", 5, Integer::sum); // 如果 "apple" 存在,合并值 (加法)
System.out.println("After merge: " + map);
compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction):
作用:根据键和当前值计算新的值。可以在操作的过程中自定义修改键值对的逻辑。
示例:
map.compute("apple", (k, v) -> (v == null) ? 1 : v * 2); // 如果 "apple" 存在,值翻倍;否则插入 1
System.out.println("After compute: " + map);
computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction):
作用:如果键不存在,则根据 mappingFunction 计算一个值,并将其插入到 HashMap 中。如果键已经存在,不会修改值。
示例:
map.computeIfAbsent("orange", k -> 4); // 如果 "orange" 不存在,插入 4
System.out.println("After computeIfAbsent: " + map);
computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction):
作用:如果键存在,则计算新的值,并更新该键。如果计算结果为 null,则移除该键。
示例:
forEach(BiConsumer<? super K, ? super V> action):
作用:对 HashMap 中的每一个键值对执行指定的动作。这对于遍历和批量操作非常方便。
示例:
map.forEach((k, v) -> System.out.println(k + " : " + v)); // 遍历并输出所有键值对
10. remove(Object key, Object value):
作用:仅当当前 HashMap 中的键与给定的值匹配时,才移除指定的键值对。如果移除成功返回 true,否则返回 false。
示例:
boolean removed = map.remove("banana", 2); // 只有当 "banana" 的值为 2 时,移除它
System.out.println("Removed 'banana' with value 2: " + removed);
11.putAll(Map<? extends K, ? extends V> paramMap):
作用:将给定的paramMap合并到当前集合。
示例:
// 创建第一个 HashMap
Map<String, Integer> fruitPrices = new HashMap<>();
fruitPrices.put("Apple", 100);
fruitPrices.put("Banana", 50);
fruitPrices.put("Cherry", 200);
// 创建第二个 HashMap
Map<String, Integer> moreFruitPrices = new HashMap<>();
moreFruitPrices.put("Orange", 80);
moreFruitPrices.put("Peach", 120);
// 使用 putAll 方法将第二个 map 中的所有元素添加到第一个 map 中
fruitPrices.putAll(moreFruitPrices);
System.out.println("All entries: " + fruitPrices.entrySet());
12. replaceAll(BiFunction<? super K, ? super V, ? extends V> paramBiFunction):
作用:对 HashMap 中的每个键值对进行遍历,并根据提供的 BiFunction(一个接受两个参数并返回一个结果的函数)对值进行替换。
示例:
// 创建 HashMap 并添加一些商品和价格
Map<String, Integer> productPrices = new HashMap<>();
productPrices.put("Laptop", 1000);
productPrices.put("Phone", 500);
productPrices.put("Tablet", 300);
// 使用 replaceAll 方法对所有价格进行 10% 的折扣
productPrices.replaceAll((product, price) -> price - (price * 10 / 100));
// 输出更新后的商品价格
System.out.println("Discounted product prices:");
for (Map.Entry<String, Integer> entry : productPrices.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
三、重温三种遍历方式
entrySet().iterator():
作用:返回一个 Iterator,可以用来遍历 HashMap 中的键值对。这是用来逐个遍历和操作元素的有效方式。
示例:
keySet().iterator():
作用:返回一个 Iterator,用于遍历所有的键。可以用来遍历 HashMap 的所有键而不直接访问值。
示例:
values().iterator():
作用:返回一个 Iterator,用于遍历所有的值。适合只关注 HashMap 的值时使用。
示例:
四、不常用方法
clone():
作用:创建并返回此 HashMap 实例的浅表副本。副本包含与原始映射相同的键和值,但键和值本身不会被深复制(也就是说,复制的仅是引用,非对象本身)。
示例:
equals(Object o):
作用:比较指定对象与此 HashMap 是否相等。如果两个 HashMap 包含相同的键值对,则返回 true。
示例:
hashCode():
作用:返回此 HashMap 的哈希码值。hashCode 依赖于 HashMap 中所有键值对的哈希值。
示例:
五、其他特性
负载因子(Load Factor):
HashMap 在超过其容量的一定比例(默认是 0.75)时,会进行动态扩展。较高的负载因子允许更多的元素存储在较小的空间内,但会降低查询效率;较低的负载因子增加了查询效率,但会消耗更多的内存。我们可以通过构造函数自定义初始容量和负载因子:
线程安全性:
HashMap 是非线程安全的,多个线程同时操作时可能会出现并发问题。对于线程安全的版本,可以使用 Collections.synchronizedMap() 包装 HashMap:
通过这些方法和特性,HashMap 提供了极大的灵活性和效率,适用于多种应用场景。
3.性能相关特性
动态扩展:当 HashMap 中的元素数量超过当前容量与负载因子的乘积时,它会进行扩容操作。这意味着哈希表会重新分配更多的桶来存储元素,从而保持较好的查找性能。
时间复杂度:大多数情况下,HashMap的查找、插入和删除操作的时间复杂度是O(1),但在最坏情况下(所有元素都被哈希到相同的桶中),时间复杂度可能会退化为O(n)。
工欲善其事必先利其器,通过整理这些方法,希望我们可以更灵活地使用 HashMap,减少不必要轮子的发明,在不同的应用场景中灵活地调整其性能或功能。
领取专属 10元无门槛券
私享最新 技术干货