Java `computeIfAbsent` 方法

前言

Java 8引入了多个新的方法来简化Map接口的使用,其中computeIfAbsent尤为引人注目。它不仅简化了键值对的管理和计算逻辑,还为开发者提供了在并发环境中进行线程安全操作的便利。

computeIfAbsent 深入剖析
方法签名
V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)
  • 参数:

    • key: 要查找或插入的键。
    • mappingFunction: 如果键不在映射中,则使用此函数来计算要插入的值。该函数不会被调用,如果键已经存在于映射中。
  • 返回值: 返回给定键对应的值;如果不存在这样的值并且提供了mappingFunction,则先通过mappingFunction计算新值,然后将其插入映射,并返回这个新值。

  • 原子性: computeIfAbsent 方法是原子性的,这意味着在一个多线程环境中,当两个线程同时尝试为同一个不存在的键计算值时,只有一个线程会成功执行mappingFunction,另一个线程将会得到由第一个线程计算的结果。

内部机制

computeIfAbsent 的核心在于它的原子性和懒加载特性。当你调用computeIfAbsent时,它首先检查提供的键是否存在于映射中。如果存在,则直接返回相应的值。如果不存在,它将调用mappingFunction来计算新值,并以原子方式将这个新值添加到映射中。这种设计确保了即使在高并发环境下也能保持数据的一致性和准确性。

使用场景与优势
  1. 缓存机制

    • 减少重复计算: 只有当键不在缓存中时才会触发计算逻辑,避免不必要的资源消耗。
    • 提高性能: 对频繁访问的数据进行缓存可以显著提升应用程序的响应速度。
    • 延迟加载: 在某些情况下,直到确实需要某个对象时才创建它,这可以节省内存和其他资源。
  2. 并发环境下的线程安全操作

    • 简化并发控制: 由于computeIfAbsent的原子性特性,在多线程环境下无需额外同步代码即可保证线程安全。
    • 降低锁争用: 相较于传统锁机制,computeIfAbsent减少了因锁而产生的等待时间,提高了系统吞吐量。
  3. 初始化默认值

    • 在构建复杂对象图或初始化配置时,computeIfAbsent 可以用于按需生成默认值,从而优化启动时间和内存使用。
示例代码与最佳实践

下面是一个具体的例子,展示了如何使用computeIfAbsent来填充用户ID到用户名字的映射,模拟了一个简单的缓存系统。同时,我们将展示一些最佳实践,确保代码的健壮性和效率。

import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
import java.util.Optional;

public class ComputeIfAbsentExample {

    private static final Map<Integer, String> idToName = new ConcurrentHashMap<>();

    public static void main(String[] args) {
        // 初始化缓存
        initializeCache();

        // 访问缓存中的值
        accessCachedValues();
    }

    private static void initializeCache() {
        // 假设我们有一个方法可以根据ID获取用户名字
        for (int i = 1; i <= 2; i++) {
            idToName.computeIfAbsent(i, ComputeIfAbsentExample::getNameById);
        }
    }

    private static void accessCachedValues() {
        System.out.println(idToName); // 输出 {1="Alice", 2="Bob"}
        
        // 尝试访问不存在的键
        Optional<String> name = Optional.ofNullable(
            idToName.computeIfAbsent(3, ComputeIfAbsentExample::getNameById)
        );
        System.out.println("Accessed non-existent key: " + name.orElse("Unknown"));
    }

    private static String getNameById(Integer id) {
        // 这里可以是更复杂的逻辑,比如从数据库中查找名字
        switch (id) {
            case 1: return "Alice";
            case 2: return "Bob";
            case 3: return "Carol";
            default: throw new IllegalArgumentException("Unknown ID");
        }
    }
}

在这个例子中,我们使用了ConcurrentHashMap来确保线程安全。此外,通过initializeCacheaccessCachedValues 方法,我们演示了如何初始化缓存以及如何访问缓存中的值。对于不存在的键(如ID为3的情况),computeIfAbsent 依然能够正确地计算出相应的值并添加到映射中。我们还使用了Optional类来处理可能为空的结果,增强了代码的安全性。

性能考量与优化建议
  1. 选择合适的映射类型

    • 根据应用的需求选择适当的Map实现类。例如,在高并发读写场景下,推荐使用ConcurrentHashMap,因为它提供了更好的并发性能。
  2. 谨慎选择mappingFunction

    • 确保mappingFunction的实现尽可能轻量级,因为它是每次遇到不存在的键时都会被调用的。对于耗时的操作,考虑异步化或批量处理。
  3. 考虑缓存策略

    • 设计合理的缓存失效策略,以避免缓存过期或溢出问题。可以考虑使用第三方库(如Caffeine)来管理复杂缓存需求。
    • 实现LRU(最近最少使用)、LFU(最不经常使用)等淘汰算法来限制缓存大小。
  4. 异常处理

    • 注意mappingFunction可能抛出的异常,并根据业务逻辑决定如何处理这些异常情况。可以在mappingFunction内捕获异常,或者在调用computeIfAbsent的地方处理异常。
  5. 测试与监控

    • 编写单元测试验证computeIfAbsent的行为,特别是边界条件和并发情况。
    • 添加日志记录或使用监控工具跟踪缓存命中率、错误率等关键指标,以便及时发现问题。
结语

computeIfAbsent不仅简化了代码,提高了可读性,还在特定场景下提供了更好的性能和线程安全性。它是Java开发者工具箱中的一个重要成员,值得我们在日常开发中加以利用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/948709.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java通过谷歌邮箱Gmail直接发送邮件的三种方式

错误 Connected to the target VM, address: 127.0.0.1:52082, transport: socketException in thread "main" javax.mail.MessagingException: Got bad greeting from SMTP host: smtp.gmail.com, port: 587, response: [EOF] at com.sun.mail.smtp.SMTPTransp…

WSDM 2025 | 时间序列(time series)论文总结

AWSDM 2025于2025年3月10号到14号在德国汉诺威举行&#xff08;Hannover, Germany&#xff09; 本文总结了WSDM 2024有关时间序列&#xff08;time series&#xff09;的相关论文&#xff0c;如有疏漏&#xff0c;欢迎大家补充。&#xff08;没有时空数据相关的论文&#xff0…

反直觉导致卡关-迫击炮谜题

这个谜题&#xff0c;在两周目中先后卡了我至少三个小时&#xff0c;先后缓慢装填并发射迫击炮弹尝试了数百次。 一周目卡了很久&#xff0c;稀里糊涂的过了&#xff0c;想不到二周目还会卡那么久。 研究了很多播主的攻略&#xff0c;但还是一头雾水&#xff0c; 直到分析其…

庐山派K230学习日记4 PWM控制

1 本节介绍​ &#x1f4dd;本节您将学习如何通过将K230开发板的GPIO引脚复用为PWM功能并输出PWM信号&#xff1b;实现输出PWM信号及控制板载无源蜂鸣器发出声音。 &#x1f3c6;学习目标 1️⃣如何将GPIO引脚配置为PWM模式&#xff0c;通过40Pin排针中的部分引脚来输出PWM信号…

c语言的文件操作与文件缓冲区

目录 C语言文件操作函数汇总 简单介绍文件 为什么使用文件 什么是文件 文件名 二进制文件和文本文件 流和标准流 流 标准流 文件指针 文件的打开和关闭 文件的顺序读写 顺序读写函数介绍 文件的随机读写 fseek ftell rewind 文件读取结束的判定 文件缓冲区 缓…

嵌入式linux中socket控制与实现

一、概述 1、首先网络,一看到这个词,我们就会想到IP地址和端口号,那IP地址和端口各有什么作用呢? (1)IP地址如身份证一样,是标识的电脑的,一台电脑只有一个IP地址。 (2)端口提供了一种访问通道,服务器一般都是通过知名端口号来识别某个服务。例如,对于每个TCP/IP实…

Nginx:动静分离

什么是动静分离? 动静分离 是指将网站中的静态资源(如图片、样式表、脚本等)和动态内容(如 PHP、Python、Node.js 等后端生成的内容)分开部署和处理。这样做的好处是可以利用不同的服务器或缓存策略来优化不同类型的资源。 动静分离的好处 提高性能:静态资源可以直接从…

PADS Layout 差分线设计规则及其设计规则约束的详细过程步骤

一般我们的电路板有很多的差分线,有90欧姆的差分线,也有100欧姆的差分线,90欧姆的差分线主要是针对USB的差分线,特别是对于USB HUB的板子,那么我们就要设置差分线。一般我们设置差分线,一般要切换到Router里面来设置,如下所示: 那么设置差分对,一般要对原理图和Router…

计算机网络--路由表的更新

一、方法 【计算机网络习题-RIP路由表更新-哔哩哔哩】 二、举个例子 例1 例2

概述(讲讲python基本语法和第三方库)

我是北子&#xff0c;这是我自己写的python教程&#xff0c;主要是记录自己的学习成果方便自己日后复习&#xff0c; 我先学了C/C&#xff0c;所以这套教程中可能会将很多概念和C/C去对比&#xff0c;所以该教程大概不适合零基础的人。 it seems that python nowadays 只在人工…

redux用法总结

redux用法总结 目录 基本概念工作原理核心概念基本使用异步操作 Redux ThunkRedux Saga React 集成Redux Toolkit最佳实践 基本概念 什么是 Redux&#xff1f; Redux 是一个可预测的状态容器&#xff0c;用于管理 JavaScript 应用的状态。它遵循三个基本原则&#xff1a; …

Gitee上传项目代码教程(详细)

工具必备&#xff1a;Git Bash 上传步骤 1.在Gitee创建项目仓库 2.进入本地项目目录 右键打开Git Bash here 3.配置用户名和邮箱 如果之前给git配置过用户名和邮箱可跳过 查看Git是否配置成功&#xff1a;git config --list git config --global user.name "xxx"…

ARM CCA机密计算安全模型之安全生命周期管理

安全之安全(security)博客目录导读 目录 一、固件启用的调试 二、CCA系统安全生命周期 三、重新供应 四、可信子系统与CCA HES 启用 CCA&#xff08;机密计算架构&#xff09;的安全系统是指 CCA 平台的实现处于可信状态。 由于多种原因&#xff0c;CCA 启用系统可能处于不…

计算机视觉CV期末总复习

1.计算机视觉基础 数字图像表示 二值图像 仅包含黑白两种颜色的图像&#xff0c;只使用1个比特为&#xff08;0黑或1白&#xff09;表示 彩色图像&#xff1a;分不同的颜色空间 gray灰度图像 每个像素只有一个采样颜色&#xff0c;取值范围0--255&#xff0c;为8比特位&a…

web安全常用靶场

这里写自定义目录标题 phpstydy2018pikachuxss-labs phpstydy2018 网盘地址 提取码: nxnw ‌phpStudy是一款专为PHP开发者设计的集成环境工具&#xff0c;主要用于简化PHP开发环境的搭建过程。‌ 它集成了Apache、MySQL、PHP等核心组件&#xff0c;用户只需进行一次性安装&a…

每天40分玩转Django:Django实战 - 在线打印服务系统

Django实战 - 在线打印服务系统 一、系统功能概览表 模块主要功能技术要点文件上传PDF/Word文件上传、文件验证文件处理、MIME类型验证异步处理文件转换、打印队列Celery、Redis通知邮件打印状态通知、订单确认SMTP、邮件模板 二、系统架构设计 2.1 模型设计 # models.py …

WPS计算机二级•数据查找分析

听说这里是目录哦 通配符&#x1f30c;问号&#xff08;?&#xff09;星号&#xff08;*&#xff09;波形符&#xff08;~&#xff09; 排序&#x1f320;数字按大小排序以当前选定区域排序以扩展选定区域排序 文字按首字母排序 快速筛选分类数据☄️文字筛选数字筛选颜色筛选…

基于海思soc的智能产品开发(camera sensor的两种接口)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 对于嵌入式开发设备来说&#xff0c;除了图像显示&#xff0c;图像输入也是很重要的一部分。说到图像输入&#xff0c;就不得不提到camera。目前ca…

网安入门之MySQL后端基础

数据库 (Database) 数据库是指长期存储在计算机中的&#xff0c;有组织、可共享的数据集合。它通过表、列、行等结构来组织数据&#xff0c;目的是使数据可以高效存储、检索和管理。数据库通常包括多个表&#xff0c;每个表存储与特定主题或对象相关的数据 数据库管理系统 (D…

概率基本概念 --- 离散型随机变量实例

条件概率&独立事件 随机变量 - 离散型随机变量 - 非离散型随机变量 连续型随机变量奇异性型随机变量 概率表示 概率分布函数概率密度函数概率质量函数全概率公式贝叶斯公式 概率计算 数学期望方差协方差 计算实例 假设有两个离散型随机变量X和Y&#xff0c;它们代…