java map接口_Java Map接口的默认方法

Java Map接口的默认方法,如果 Map 中包含元素,用户希望替换元素;如果 Map 中没有元素,用户希望添加元素;此外,用户还希望执行其他相关操作。使用 java.util.Map 接口新增的各种默认方法,如 computeIfAbsent、computeIfPresent、replace、merge 等。

Java Map接口的默认方法 问题描述

如果 Map 中包含元素,用户希望替换元素;如果 Map 中没有元素,用户希望添加元素;此外,用户还希望执行其他相关操作。

Java Map接口的默认方法 解决方案

使用 java.util.Map 接口新增的各种默认方法,如 computeIfAbsent、computeIfPresent、replace、merge 等。

Java Map接口的默认方法 具体实例

从 Java 1.2 引入集合框架(collections framework)起,Map 接口就已存在。Java 8 为 Map 接口引入了一些新的默认方法,如表 5-1 所示。

表5-1:Map接口定义的默认方法

方法

描述

Compute

根据现有的键和值计算新的值

computeIfAbsent

如果键存在,返回对应的值,否则通过提供的函数计算新的值并保存

computeIfPresent

计算新的值以替换现有的值

forEach

对 Map 进行迭代,将所有键和值传递给 Consumer

getOrDefault

如果键在 Map 中存在,返回对应的值,否则返回默认值

merge

如果键在 Map 中不存在,返回提供的值,否则计算新的值

putIfAbsent

如果键在 Map 中不存在,将其关联到给定的值

remove

如果键的值与给定的值匹配,删除该键的条目

replace

将现有键的值替换为新的值

replaceAll

将 Map 中每个条目的值替换为对当前条目调用给定函数后的结果

Java 8 为已有十多年历史的 Map 接口引入了不少新方法,某些方法能为开发提供极大的便利。

1. computeIfAbsent

computeIfAbsent 方法的完整签名如下:

在创建方法调用结果的缓存时,computeIfAbsent 尤其有用。我们以经典的斐波那契数递归计算为例进行讨论。如例 5-8 所示,任何大于 1 的斐波那契数等于前两个斐波那契数之和 5。

例 5-8 斐波那契数递归计算

➊ 效率极低

上述代码的问题在于需要进行大量重复的计算(如 fib(5) = fib(4) + fib(3) = fib(3) + fib(2) + fib(2) +fib(1) = ...),导致程序效率极低。可以利用缓存解决这个问题,函数式编程将这种技术称为记忆化(memoization)。如例 5-9 所示,我们将结果修改为存储 BigInteger 实例。

例 5-9 利用缓存计算斐波那契数

➊ 如果键的值在缓存中存在,返回对应的值,否则计算新的值并保存

本例采用缓存计算斐波那契数,其中键为提供的数字,值为相应的斐波那契数。computeIfAbsent 方法在缓存中搜索给定的数字,存在则返回对应的值,否则使用提供的 Function 计算新的值,将其保存在缓存中并返回。对单一方法而言,这已是很大的改进。

2.computeIfPresent

computeIfPresent 方法的完整签名如下:

仅当与某个值关联的键在 Map 中存在时,computeIfPresent 才会更新该值。假设我们需要解析一个文本,并计算文本中每个单词的出现次数。这种一致性(concordance)计算在实际中并不鲜见。如果仅对某些特定单词感兴趣,可以使用 computeIfPresent 方法进行更新,如例 5-10 所示。

例 5-10 仅更新特定单词的出现次数

❶ 将特定单词置于映射中,并将计数器设置为 0

❷ 读取文本,仅更新特定单词的出现次数

通过将特定单词置于映射中并将初始计数器设置为 0,就能让 computeIfPresent 方法只更新这些值。

如例 5-11 所示,对一段文本以及一个逗号分隔的单词列表执行上述程序,可以得到所需的结果。

例 5-11 调用 countWords 方法

可以看到,仅当所需单词是映射中的键时,程序才会更新它们的出现次数。与之前一样,采用 Map 接口定义的默认方法 forEach 打印值,该方法传入 BiConsumer,其参数为键和值。

3.其他方法

replace 方法的用法与 put 方法类似,前提是键已经存在。如果键不存在,replace 不会执行任何操作,而 put 将添加一个空键(null key),不过这可能并非如我们所愿。

replace 方法包括两种重载形式:

对于第一种形式,如果键在映射中存在,则将其替换为对应的值;对于第二种形式,如果键的值与指定的值相等,则将其替换为新的值。

使用不存在的键调用 Map 接口的 get 方法将返回 null,这个令人头疼的问题可以通过 getOrDefault 方法解决。该方法仅返回默认值,但不会将键添加到映射中。

getOrDefault 方法的签名如下:

如果键在映射中不存在,getOrDefault 方法将返回默认值,但不会将这个键添加到映射中。

merge 方法非常有用,其完整签名如下:

对于一段给定的文本,假设我们希望统计所有单词(而不仅是特定单词)的出现次数,那么通常需要考虑两种情况:如果单词已经在映射中,则更新计数器;如果单词不在映射中,则将其置于映射中并使计数器加 1。可以通过 merge 方法简化这个过程,如例 5-12 所示。

例 5-12 merge 方法的应用

❶ 将字符串转换为小写字母并删除标点符号

❷ 更新给定单词的计数器

merge 方法传入键和默认值。如果键在映射中不存在,则插入默认值,否则根据原有值并使用 BinaryOperator(本例为 Integer::sum)计算出新的值。

本范例讨论了 Map 接口新增的默认方法,希望这些方法能为程序开发带来便利。

5大部分读者想必都听过这个笑话:“据说今年的斐波那契会议将和前两年一样好。”

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值