惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
人人都是产品经理
人人都是产品经理
Cisco Talos Blog
Cisco Talos Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
V
V2EX
博客园 - 三生石上(FineUI控件)
Martin Fowler
Martin Fowler
WordPress大学
WordPress大学
D
Docker
S
SegmentFault 最新的问题
博客园 - 聂微东
美团技术团队
Apple Machine Learning Research
Apple Machine Learning Research
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Last Week in AI
Last Week in AI
M
MIT News - Artificial intelligence
F
Fortinet All Blogs
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
The GitHub Blog
The GitHub Blog
GbyAI
GbyAI
L
LangChain Blog
Vercel News
Vercel News
博客园 - 叶小钗
MongoDB | Blog
MongoDB | Blog
Stack Overflow Blog
Stack Overflow Blog
H
Help Net Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The Cloudflare Blog
Engineering at Meta
Engineering at Meta
T
Threat Research - Cisco Blogs
T
Threatpost
Scott Helme
Scott Helme
T
Tailwind CSS Blog
Latest news
Latest news
Stack Overflow Blog
Stack Overflow Blog
Blog — PlanetScale
Blog — PlanetScale
The Register - Security
The Register - Security
罗磊的独立博客
P
Proofpoint News Feed
腾讯CDC
S
Schneier on Security
雷峰网
雷峰网
A
About on SuperTechFans
T
Tenable Blog
F
Full Disclosure
Cyberwarzone
Cyberwarzone
博客园_首页
有赞技术团队
有赞技术团队
K
Kaspersky official blog

任霏博客

我将关闭服务器:AI彻底掐死了奄奄一息的个人博客 - 博客文章 - 任霏的个人博客网站 Vibe Coding 实现本地模型 Token 自由 IntelliJ IDEA + LM Studio + LM Link + Continue 1Password涨价后,别急着退订1Password,这个操作能帮你省25% - 博客文章 - 任霏的个人博客网站 我,吃饱了撑的注册了个域名,Cloudflare账号没了,不建议将域名放在Cloudflare - 博客文章 - 任霏的个人博客网站 临时邮箱:保护隐私与免骚扰的新方式 - 博客文章 - 任霏的个人博客网站 价值4100万美元SOL被盗SwissBorg在Solana上遭遇安全事件超200万枚ETH排队退出质押 - 博客文章 - 任霏的个人博客网站 注意 Web3 钱包遭遇 NPM 超大规模供应链攻击投毒事件 - 博客文章 - 任霏的个人博客网站 我受到以太坊ERC-20假代币地址投毒攻击记录一下大家谨防上当受骗 - 博客文章 - 任霏的个人博客网站 在2025年使用显卡 NVIDIA RTX 2080 Ti 挖矿收益记录和分析还能不能挖矿 - 博客文章 - 任霏的个人博客网站 分享我是如何成功戒烟的经验(包含失败的经验) - 博客文章 - 任霏的个人博客网站 在 OpenWRT 中配置 PassWall2 插件的教程记录 - 博客文章 - 任霏的个人博客网站 Office Professional Plus 2019 VL 版下载与 KMS 激活 - 博客文章 - 任霏的个人博客网站 最近几天我的 CDN 流量受到来自电信[山东烟台]、[江苏扬州]两地家庭宽带的攻击 - 博客文章 - 任霏的个人博客网站 自建AI服务器使用PVE配置显卡直通虚拟机安装驱动、CUDA和cuDNN运行LLM大模型进行AI炼丹 - 博客文章 - 任霏的个人博客网站 各代英特尔Intel芯片组主板适配兼容的CPU和DDR内存数据统计 - 博客文章 - 任霏的个人博客网站 GitLab Global 国际站将在60天内删除中国大陆、香港、澳门地区的账号 - 博客文章 - 任霏的个人博客网站 Github Copilot Free 开放免费版所有人均可使用 OpenAI GPT-4o、Anthropic Claude 3.5 AI 代码生成服务 - 博客文章 - 任霏的个人博客网站 Cloudflare 更新了订阅协议明确禁止优选IP和搭建梯子的行为 - 博客文章 - 任霏的个人博客网站 Linux(systemd)手动离线安装二进制(binary)MairaDB数据库指定版本 - 博客文章 - 任霏的个人博客网站 流程引擎 Flowable/Activiti 无法启动报错:liquibase - Waiting for changelog lock.... - 博客文章 - 任霏的个人博客网站 Spring Boot 全局异常捕获 ControllerAdvice 无法捕获 过滤器(Filter)和拦截器(Interceptor)中的异常 - 博客文章 - 任霏的个人博客网站 Freenom 收回了全部免费域名(.tk/.cf/.gq/.ga/.ml) - 博客文章 - 任霏的个人博客网站 Alibaba Druid 数据库连接池 takeLast() AQS 死锁导致程序无响应 - 博客文章 - 任霏的个人博客网站 你的网站加入 HSTS preload 预加载列表了吗 - 博客文章 - 任霏的个人博客网站 我的博客网站接入使用 Cloudflare 的架构分享 - 博客文章 - 任霏的个人博客网站 在 Ubuntu 上的 Nginx 高并发配置实践 - 博客文章 - 任霏的个人博客网站 技术分析黑客敲诈勒索站长的新手法百度对此也无能为力 - 博客文章 - 任霏的个人博客网站 百度站长平台快速收录权限和sitemap提交权限被全部收回 - 博客文章 - 任霏的个人博客网站 极狐 GitLab 免费时代结束不升级付费账号将禁止登陆 - 博客文章 - 任霏的个人博客网站 免费.ml域名10年委托合同到期被马里共和国收回域名经营权 - 博客文章 - 任霏的个人博客网站 从极狐Gitlab看各种中间件技术选型 - 博客文章 - 任霏的个人博客网站 时隔十年首次收到 Google AdSense 的付款 - 博客文章 - 任霏的个人博客网站 ga域名被加蓬共和国从Freenom公司手中收回域名经营权 - 博客文章 - 任霏的个人博客网站 Freenom 被 Meta(Facebook) 起诉导致暂停 .tk/.ga/.ml/.cf/.gq 等新域名注册 - 博客文章 - 任霏的个人博客网站 生花妙笔信手来 – 基于 Amazon SageMaker 使用 Grounded-SAM 加速电商广告素材生成 [1] - 博客文章 - 任霏的个人博客网站 github.renfei.net 不再完整代理 Github 页面改为代理指定文件 - 博客文章 - 任霏的个人博客网站 优雅的源代码管理(三):本地优雅的使用 Git Rebase 变基 - 博客文章 - 任霏的个人博客网站 优雅的源代码管理(二):Git 的工作原理 - 博客文章 - 任霏的个人博客网站 优雅的源代码管理(一):版本控制系统 VCS(Version Control System)与软件配置管理 SCM(Software Configuration Management) - 博客文章 - 任霏的个人博客网站 ChatGPT 开发商 OpenAI 买下极品域名 AI.com - 博客文章 - 任霏的个人博客网站 火爆的 AI 人工智能 ChatGPT 国内注册教程、使用方式和收费标准 - 博客文章 - 任霏的个人博客网站 解决 SpringCloud 中 bootstrap.yml 不识别 @activatedProperties@ 参数 - 博客文章 - 任霏的个人博客网站 Cron表达式书写教程搞定Linux、Spring、Quartz的定时任务 - 博客文章 - 任霏的个人博客网站 阿里云香港可用区C发生史诗级故障 - 博客文章 - 任霏的个人博客网站 国产统信UOS服务器操作系统V20提供免费使用授权 - 博客文章 - 任霏的个人博客网站 开源站长推送工具效果评测推荐(百度/必应/谷歌) - 博客文章 - 任霏的个人博客网站 获取公网IP服务「ip.renfei.net」升级增加地理定位数据字段公示 - 博客文章 - 任霏的个人博客网站 腾讯微信成为 GitHub 秘钥扫描合作伙伴 - 博客文章 - 任霏的个人博客网站 免费设置亚马逊远程桌面 - 博客文章 - 任霏的个人博客网站 我关站了-个人备案核查要求关闭论坛系统 - 博客文章 - 任霏的个人博客网站 Linux 中 chmod 644、755、777权限的含义和使用方法 - 博客文章 - 任霏的个人博客网站 Spring Boot 3.0 发布啦但是我还是暂时放弃升级了 - 博客文章 - 任霏的个人博客网站 过时老旧电脑安装 Windows11 跳过 Win11 TPM、RAM、Secure Boot 最低系统要求限制检查 - 博客文章 - 任霏的个人博客网站 IT资讯网站 cnBeta.com 网站被关停域名已经被 clientHold - 博客文章 - 任霏的个人博客网站 当你 git push 时,极狐GitLab上发生了什么? - 博客文章 - 任霏的个人博客网站 昨晚接口又被日了,接口被疯狂调用的背后是人是鬼?是道德的沦丧还是人性的扭曲? - 博客文章 - 任霏的个人博客网站 Mac破解软件站MacWk下线破产了,我想分享Mac破解软件却不太敢 - 博客文章 - 任霏的个人博客网站 我和极狐GitLab的故事回顾 - 博客文章 - 任霏的个人博客网站 极狐 GitLab 可以集成石墨文档作为Wiki管理了 - 博客文章 - 任霏的个人博客网站 关于基于极狐 GitLab 的知识库探索思路 - 博客文章 - 任霏的个人博客网站 在极狐 Gitlab 流水线配置里设置镜像拉取策略 - 博客文章 - 任霏的个人博客网站 极狐 GitLab Markdown 可排序、可过滤的数据表格实现 - 博客文章 - 任霏的个人博客网站 极狐 GitLab Issue 统计的思路分享 - 博客文章 - 任霏的个人博客网站 把极狐 GitLab Runner 搬回家运行,指定专属 Runner - 博客文章 - 任霏的个人博客网站 给极狐 GitLab SaaS 安装百度统计代码统计仓库访问量 - 博客文章 - 任霏的个人博客网站 关于我在极狐GitLab造机器人这件事儿我觉得很酷 - 博客文章 - 任霏的个人博客网站 如何参与极狐GitLab开源项目成为贡献者 - 博客文章 - 任霏的个人博客网站 关于 Cloudflare R2 Storage 的使用体验测评和我的观点 - 博客文章 - 任霏的个人博客网站 西部数据(WD40NMZW) 4TB Elements(2060-800041-003)移动硬盘拆解记录 - 博客文章 - 任霏的个人博客网站 获取公网IP服务「ip.renfei.net」升级,支持根据请求头 Accept 响应不同格式数据 - 博客文章 - 任霏的个人博客网站 我站再次受到扫描攻击的公告 - 博客文章 - 任霏的个人博客网站 我站近期遭受到恶意不友好访问攻击公告 - 博客文章 - 任霏的个人博客网站 讨论下Java中的volatile和JMM(Java Memory Model)Java内存模型 - 博客文章 - 任霏的个人博客网站 Java中说的CAS(compare and swap)是个啥 - 博客文章 - 任霏的个人博客网站 大佬们在说的AQS,到底啥是个AQS(AbstractQueuedSynchronizer)同步队列 - 博客文章 - 任霏的个人博客网站 草根站长利用极狐GitLab作为图床外链 JIHULAB 101 - 博客文章 - 任霏的个人博客网站 极狐GitLab上的Building风云 - 之API如此多娇 JIHULAB 101 - 博客文章 - 任霏的个人博客网站 极狐GitLab上的Building风云 - 之Security风云再起 JIHULAB 101 极狐GitLab上的Building风云 - 之Docker风云必胜 JIHULAB 101 极狐GitLab上的Building风云 - 之Java Maven雄霸天下 JIHULAB 101 世界排名网站Alexa将于2022年5月1日停止服务 免费IP数据库IP2Location的Java版客户端与BIN文件下载 人大金仓 KingbaseES V8 R3 安装包、驱动包和 License 下载地址 极狐(GitLab)SaaS平台内测试用报告 软件设计开发经验分享:文字应当使用透明度而不是固定色值 国内版 Gitlab.cn(极狐)正在为期一个月的内测阶段中
正确使用 Optional 优雅的解决 null 空指针 NPE 异常 - 博客文章 - 任霏的个人博客网站
任霏 · 2022-01-15 · via 任霏博客

要说起 Optional 的诞生,需要先了解一下 NPE,很多面向对象编程语言中都会有 null 值,也就是空指针,在程序栈上指向了一个不存在的堆地址,当你使用这个指向不存在的堆地址对象时就会抛出一个 NullPointerException 异常,如果你没有很好的遇见到空指针的情况,那么你的程序将会崩溃。

为了解决头疼的 NPE 异常,终于有人看不下去出手了,发明了 Optional 来解决 NPE 的问题。

在开始学习 Optional 之前,我们需要先学习他解决 NPE 问题的思想,不要滥用 Optional,因为如果滥用 Optional 会发生非常混乱的局面,反而让你的代码更加复杂和难以控制,接下来我们先了解一下他解决 NPE 的思想。

首先明确的是 Optional 是一种容器来存放东西,它只是一种解决空指针的思想,你使用这种思想就可以优雅的解决 NPE 问题,如果你没明白这种思想,即使使用 Optional 也可能会造成 NPE 异常。

禁止滥用 Optional

学会新东西以后觉得好牛逼,希望应用到所有地方,恨不得将所有类都重构一遍,于是可能写出这样的代码:

String userName = Optional.ofNullable(name).orElse("")

这样写虽然没有错,正确使用了 Optional ,但是意义在哪呢?这降低了代码的可读性,并且还创造了一个 Optional 对象,浪费了系统性能,三元表达式完全可以搞定。

禁止使用 Optional 作为 Bean 类的成员

Optional 没有实现Serializable接口(不可序列化),所以可能引起系统故障,Optional 并不是让你作为类成员使用的,正确的使用方法在下面讲。

禁止 Optional 作为 Bean 类的 Setter 方法入参

除了 Optional 是不可序列化的,降低了可读性。Setter 是给成员赋值的,你作为赋值的人你不知道值是不是空吗?所以使用 Optional 作为赋值的入参是没有意义的。

禁止在集合中使用Optional

不要在List, Set, Map 等集合中使用 Optional,因为同样是没有意义的,你这么做想要解决什么?

同样,不要在 Optional 中包装入容器类型,容器一般都有自己的空值逻辑设计,不要画蛇添足。

禁止给Optional赋值null

禁止给 Optional 赋值 null,你应该使用 Optional.empty() 来赋值和表达空。

慎用get()方法

如果不检查 Optional 是否为空值就直接调用 get() 方法,就让 Optional 失去了意义。如果你不确定是否有值,那就永远不要调用 get() 方法。

正确使用Optional

在上面我们先了解了不要滥用 Optional,现在我们了解一些正确使用 Optional 的场景。

当你无法确定拿到的值是否为 null 时,就可以使用 Optional 进行包装,然后处理。

在 Bean 类的 Getter 中使用

在上面举例中禁止在 Bean 类的 Setter 中使用,理由是赋值动作是你主动调用的,你自己应当知道值是否为 null,那么根据这条理由,Bean 类的 Getter 就可以使用 Optional 返回包装值,因为获取值的时候,你无法确定获取到的值是否为 null,就需要 Optional 包装来处理。

优雅的处理复杂对象的NPE问题

在上面案例中,我们举例禁止在简单逻辑中滥用 Optional,例如:

String userName = Optional.ofNullable(name).orElse("")

正确的使用方式是在复杂对象取值时,我们就需要 Optional 来优雅的处理 null 值,举个例子,假设我们有个 User 对象,它有一个BaseInfo 成员,BaseInfo 又拥有 Email 属性,我们不确定 User 是不是 null,也不确定 BaseInfo 是否为 null,想要获取它的 Email,此处将用到多个知识点:

  • 在Bean类 Getter 中使用 Optional,这样可以构成链式调用编程

  • 使用了“::”关键字,你也可以使用 lambda 表达式来调用

  • 使用了 Optional.flatMap() 方法来转换类型

我们可以这样写:

OptionalExample,可在 https://example.renfei.net/java/OptionalExample/ 获取代码

package net.renfei;

import java.util.Optional;

public class OptionalExample {

    public static class User {
        private BaseInfo baseInfo;

        public void setBaseInfo(BaseInfo baseInfo) {
            this.baseInfo = baseInfo;
        }

        public Optional<BaseInfo> getBaseInfo() {
            return Optional.ofNullable(this.baseInfo);
        }

        public static class BaseInfo {
            private String email;

            public void setEmail(String email) {
                this.email = email;
            }

            public Optional<String> getEmail() {
                return Optional.ofNullable(this.email);
            }
        }
    }

    public static void main(String[] args) {
        // 验证如果 user 为 null 的情况
        printEmail(null);
        // 验证如果 User.BaseInfo 为 null 的情况
        User user = new User();
        user.setBaseInfo(null);
        printEmail(user);
        // 验证如果 User.BaseInfo.Email 为 null 的情况
        User.BaseInfo baseInfo = new User.BaseInfo();
        baseInfo.setEmail(null);
        user.setBaseInfo(baseInfo);
        printEmail(user);
        // 验证正常情况
        baseInfo.setEmail("i@renfei.net");
        user.setBaseInfo(baseInfo);
        printEmail(user);
    }

    public static void printEmail(User user) {
        String defaultEmail = "Unknown Email";
        // user 是外部传入的,我们也不知道 User 是否为 null
        Optional<User> optionalUser = Optional.ofNullable(user);
        // 我们需要打印 User 的 Email,如果为 null,打印默认值
        System.out.println(optionalUser
                .flatMap(User::getBaseInfo)
                .flatMap(User.BaseInfo::getEmail)
                .orElse(defaultEmail));
    }
}

经过上面的代码验证,User 任意成员或属性为 null 时都不会引起 NPE 异常,都正常的输出了默认的 Email 内容,是否给你有一些启发?

其他

除了上述我简单演示的内容,Optional 还提供了很多方法,结合函数式编程的链式调用,可以非常潇洒和优雅的解决 NPE 问题。我这篇文章不是纯教学文章,而是希望引起你的思考,找到解决问题的思路最为重要,因为要去学习不如看官方文档,我写也不是权威的,所以读者应该学习和思考 JDK 大佬们的解决思维,在自己的项目中加以利用。