当前位置: 首页 > news >正文

知识就是力量:如何优雅判空?

知识就是力量:如何优雅判空?

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

在我们的项目中,有一个 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 的思维习惯

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

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

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