文章目录
- [256. Java 集合 - 掌握 Java 的 merge () 方法:提升 Map 操作效率与灵活性的关键](#256. Java 集合 - 掌握 Java 的 merge () 方法:提升 Map 操作效率与灵活性的关键)
256. Java 集合 - 掌握 Java 的 merge () 方法:提升 Map 操作效率与灵活性的关键
在Java中,处理Map集合时,我们经常需要执行一些涉及值聚合和修改的操作。对于这些任务,computeIfAbsent() 和 merge()方法提供了非常有效的解决方案。
Merging Values(合并值)
computeIfAbsent()模式非常适合处理那些值是其他值聚合的情况。例如,当我们将多个值累积到一个可变集合(如ArrayList)中时,computeIfAbsent()可以方便地实现这一点。然而,这个模式有一个前提条件:支持聚合的结构必须是可变的,比如ArrayList。但当我们希望聚合的值是不可变的(如String),这时computeIfAbsent()就不再适用了。
为了应对这种情况,Java提供了一个非常有用的方法:merge()。merge()方法允许我们将新值合并到已经存在的值中,或者在不存在该键时直接绑定新值。
merge() 方法的工作原理
merge()方法接受三个参数:
key(键):表示你要操作的Map的键。value(值):你想要绑定到键的值。remapping BiFunction(重新映射的BiFunction):这是一个函数,接受当前的键值对中的"现有值"和"新值",并返回一个新的值来替换原来的值。
工作流程
- 如果键不在
Map中,或者该键的值为null,merge()方法直接将值绑定到该键,而不会调用remapping函数。 - 如果键已经存在并且有一个非
null值,merge()方法会调用remapping函数,传入当前的值和新的值。remapping函数返回的值会替代原来的值。 - 如果
remapping函数返回null,则该键会从Map中删除。
示例:合并字符串
假设你有一个字符串列表,你想根据字符串的长度将这些字符串分类,并且希望将长度相同的字符串合并为一个字符串,通过逗号分隔。
java
List<String> strings = List.of("one", "two", "three", "four", "five", "six", "seven");
Map<Integer, String> map = new HashMap<>();
for (String word : strings) {
int length = word.length();
map.merge(length, word, (existingValue, newWord) -> existingValue + ", " + newWord);
}
map.forEach((key, value) -> System.out.println(key + " :: " + value));
运行结果:
java
3 :: one, two, six
4 :: four, five
5 :: three, seven
解释:
- 首次合并 :当长度为
3的字符串(如"one")首次出现时,merge()方法会将其添加到Map中。 - 已有键时的合并 :当相同长度的其他字符串(如
"two"和"six")出现时,merge()会调用remapping函数,将现有值(如"one")与新值(如"two")合并为一个字符串:"one, two"。然后它会继续合并下一个字符串。
选择merge()的原因
使用merge()方法相对于直接使用putIfAbsent()或computeIfAbsent(),具有更高的灵活性。尤其是在需要合并值的情况下,merge()不仅仅是添加新的值,它还提供了更多控制的能力,尤其是在已有值时如何合并。
性能考虑
在computeIfAbsent()和merge()方法中,你可能会注意到Lambda表达式的参数总是能够直接从上下文中获取。这些Lambda表达式会捕获上下文中的变量,因此推荐尽量避免使用捕获上下文的Lambda,而是使用非捕获Lambda,以提高性能。
总结
computeIfAbsent():适用于通过键生成新的值(如使用List等可变类型作为值),可以避免重复创建对象。merge():适用于在键存在时合并现有值与新值,或在键不存在时直接设置新值,适合不可变对象(如String)的合并操作。
这两种方法都可以帮助我们高效地处理复杂的映射操作,减少代码冗余,提高代码的可维护性和性能。