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

推荐订阅源

cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Hacker News - Newest:
Hacker News - Newest: "LLM"
N
News and Events Feed by Topic
PCI Perspectives
PCI Perspectives
Help Net Security
Help Net Security
C
CXSECURITY Database RSS Feed - CXSecurity.com
V2EX - 技术
V2EX - 技术
Google Online Security Blog
Google Online Security Blog
Hacker News: Ask HN
Hacker News: Ask HN
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
P
Palo Alto Networks Blog
The Last Watchdog
The Last Watchdog
C
Cyber Attacks, Cyber Crime and Cyber Security
Security Latest
Security Latest
Application and Cybersecurity Blog
Application and Cybersecurity Blog
W
WeLiveSecurity
Cloudbric
Cloudbric
O
OpenAI News
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Webroot Blog
Webroot Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
S
Schneier on Security
罗磊的独立博客
雷峰网
雷峰网
S
Security Affairs
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
L
LINUX DO - 热门话题
NISL@THU
NISL@THU
量子位
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园 - 【当耐特】
博客园 - Franky
S
Security @ Cisco Blogs
Project Zero
Project Zero
AI
AI
T
Troy Hunt's Blog
Latest news
Latest news
Simon Willison's Weblog
Simon Willison's Weblog
S
SegmentFault 最新的问题
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
T
Tailwind CSS Blog
The Cloudflare Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Scott Helme
Scott Helme
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Jina AI
Jina AI
I
Intezer
V
Visual Studio Blog
Cyberwarzone
Cyberwarzone
博客园 - 叶小钗

博客园 - buguge

最差实践(bad-practice):开发者在方法里直接实例化线程池对象,然后...(应用gg了) 【HttpClient最差实践(bad-practice)】开发者在 http 工具方法中直接实例化 HttpClient,然后…… Crypto、Cipher与Password:Java加密开发的三个核心概念 20260604SR超时问题排查 推敲见文章:从 `try..catch` 看异常日志打印的正确姿势 #解决问题要彻底# 慢SQL治理完成后,如何防止同类问题“死灰复燃”? 从合同甲方是荒谬的“JD”谈起:软件开发不应遗忘的“常识” 别留小尾巴/尽快剪掉小尾巴:从一次“ABA”字段重命名,谈谈“解决问题要彻底” 常见的OOM错误 ( OutOfMemoryError全类型详解) 开发者暴露了一个无需授权访问的裸接口,我问:如果有人暴力请求怎么办? 【SQL性能优化篇】有了!治理慢SQL“WHERE create_time ORDER BY id”的良药---规避“Using filesort”性能杀手 高效查询商户日终余额:一个SQL的优化实践 Hutool 的 `TimedCache` 到期会自动清理吗? ——————hutool cache的"惰性清理"和"定期清理" Fastjson枚举反序列化:当字符串不是枚举常量名时,会发生什么? fastjson-EnumDeserializer类及源码分析 `UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only` 异常解析 认识2个单词:goal/target —————— 为什么Maven是 "goal" 而不是 "target"? 聚合系统设计:策略模式(Strategy Pattern)在银行通道对接场景中的应用 这样构建对象,太帅了!—— 阶梯式Builder模式与代码整洁之道 注意!字段数据类型不匹配,这个sql会很慢 还在用ArrayList?用HashSet吧!--性能对比 分页查询还在用create_time去做降序? 从 synchronized 到 ConcurrentHashMap:一个小小的并发控制策略升级优化,证明我还是初级程序员 面试题沟通整理 【研发笔记20260120】值得记录:靠谱程序员的回聘 研发笔记:如何消除长字符串的秘钥数据对RPC负荷、日志量、系统安全所带来的伤害? 未给entity的主属性赋值,Mybatisplus却抛出了type mismatch异常。——————分享一下Mybatisplus主键填充机制 在java中实现c#的int.TryParse方法 灵活用工平台-连续劳务所得税-计算器-工具类,拿走不谢 Apollo场景建议配置指南:充分发挥分布式配置中心优势
知识VS技能:如何优雅判空?
buguge · 2026-06-21 · via 博客园 - buguge

知道不等于会用,会用才是真本事

在我们的项目中,有一个 EnterpriseContext 工具类,用于管理当前登录企业的 Session 信息。代码很简单:

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

public class EnterpriseContext {

    public static final String ENTERPRISE_SESSION = "enterprise_info";

    private static HttpSession getSession() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        return request.getSession();
    }

    public static void setEnterpriseVo(EnterpriseVO loginEnterprise) {
        getSession().setAttribute(ENTERPRISE_SESSION, loginEnterprise);
    }

    public static EnterpriseVO getEnterpriseVo() {
        return (EnterpriseVO) getSession().getAttribute(ENTERPRISE_SESSION);
    }
}

这段代码在非 Web 请求上下文中调用时会抛出 NullPointerException。比如:

  • 在单元测试中调用
  • 在定时任务的后台线程中调用
  • 在脱离了当前请求的异步任务中调用

因为 RequestContextHolder.getRequestAttributes() 在没有绑定请求的情况下会返回 null,后续的 .getRequest() 就直接 NPE 了。

开发者的修复:if 判空

我把问题反馈给开发者,他很快就给出了修复版本:

private static HttpSession getSession() {
    ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    if (attributes == null) {
        return null;
    }
    HttpServletRequest request = attributes.getRequest();
    return request.getSession();
}

public static void setEnterpriseVo(EnterpriseVO loginEnterprise) {
    HttpSession session = getSession();
    if (session != null) {
        session.setAttribute(ENTERPRISE_SESSION, loginEnterprise);
    }
}

public static EnterpriseVO getEnterpriseVo() {
    HttpSession session = getSession();
    if (session != null) {
        return (EnterpriseVO) session.getAttribute(ENTERPRISE_SESSION);
    }
    return null;
}

NPE 确实被修复了。代码逻辑正确,也能正常跑。不过,我跟开发者说,代码不够优雅。

开发者思考片刻,跟另一个小伙面面相觑,反来追问我:

"那你的优雅方案是什么?"

我一笑置之,没有直接答复。

如果我提示使用"Optional",以他的技术能力,一定立刻就能写出优雅的版本。但我不说,他却想不到。

问题出在哪?

知道 基于Optional进行优雅判空的知识。但在这个场景下,他的思维被"if 判空"这个惯用模式束缚住了,没有主动想到把 Optional 用起来。

知识就在那里,他却没用上。

进阶方案:Optional 链式调用

private static Optional<HttpSession> getSession() {
    return Optional.ofNullable((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
            .map(ServletRequestAttributes::getRequest)
            .map(HttpServletRequest::getSession);
}

public static void setEnterpriseVo(EnterpriseVO loginEnterprise) {
    getSession().ifPresent(session -> session.setAttribute(ENTERPRISE_SESSION, loginEnterprise));
}

public static EnterpriseVO getEnterpriseVo() {
    return (EnterpriseVO) getSession()
            .map(session -> session.getAttribute(ENTERPRISE_SESSION))
            .orElse(null);
}

对比分析

if 版本的痛点

// 三步走:先取值,再判断,最后使用
ServletRequestAttributes attributes = ...;
if (attributes == null) {
    return null;
}
HttpServletRequest request = attributes.getRequest();
return request.getSession();
  • 引入了临时变量 attributes
  • 多了一个分支判断和 return
  • 代码行数多,阅读时需要跳转

Optional 版本的亮点

// 一行链式调用,意图一目了然
return Optional.ofNullable(...)
        .map(ServletRequestAttributes::getRequest)
        .map(HttpServletRequest::getSession);

维度 if 版本 Optional 版本
代码行数 更多 更少
临时变量 需要多个 无需
空值语义 隐式(靠 return null) 显式(Optional 类型)
嵌套层级 多层 if 可能嵌套 链式调用保持扁平
编译期安全 容易漏判 强制处理空值
可读性 常规 更声明式

更深一层:知识 vs 技能 --知识就是力量,但更重要的是运用知识的能力

这个小故事反映了一个普遍现象:

知识的掌握 ≠ 知识的运用

很多开发者都能准确说出 Optional 是用来"避免空指针异常"的。但到了实际编码时,第一反应仍然是 if (obj != null)

这种现象太常见了:

  • 知道"策略模式",但遇到 if-else 泛滥时想不起来用
  • 知道"Stream API",但处理集合时还是写 for 循环
  • 知道"Lambda 表达式",但写代码时仍然用匿名内部类

知道是知识,用出来才是技能

知识的价值不在于你拥有多少,而在于你在恰当的时机能否想起并使用它。

面试中能流畅背诵"Optional 的四大方法"、"Stream 的中间操作与终止操作",这当然算知识。但如果写出来的代码依然是下面这样的,那这个知识就没有真正转化为能力,只能算是“八股文”式的低效学习。

List<String> result = new ArrayList<>();
for (String s : list) {
    if (s != null && s.startsWith("A")) {
        result.add(s);
    }
}

知识只是原材料,思考才是加工厂。不经过主动思考的知识,就像一本从未翻阅的字典——它就在书架上,但你遇到生字时却想不起来去查。

结语

回到最初的那个问题。开发者问我的"优雅方案"到底是什么?

其实不是 Optional,而是在合适的场景下主动想起并运用 Optional 的思维习惯

技术工具永远在变,但"学以致用"的能力是贯穿始终的。

知道很多道理,却依然写不好代码——原因往往不是知识不够,而是思考不够。

知识就是力量,但运用知识的能力,才是真正的力量