JAVA 代码赏析:优雅的 Token 提取策略
背景我们常见的丑陋写法在处理第三方 API 响应时由于不同服务返回的 Token 字段名不统一很多开发者会写出这样的代码❌ 反面教材嵌套 if-else 地狱privateStringparseToken(StringresponseText){if(StringUtils.isBlank(responseText)){returnnull;}try{JSONObjectjsonJSON.parseObject(responseText);// 第一层尝试Stringtokenjson.getString(access_token);if(StringUtils.isNotBlank(token)){returntoken;}// 第二层尝试tokenjson.getString(accessToken);if(StringUtils.isNotBlank(token)){returntoken;}// 第三层尝试tokenjson.getString(token);if(StringUtils.isNotBlank(token)){returntoken;}// 第四层尝试从 data 中找JSONObjectdatajson.getJSONObject(data);if(data!null){tokendata.getString(access_token);if(StringUtils.isNotBlank(token)){returntoken;}tokendata.getString(accessToken);if(StringUtils.isNotBlank(token)){returntoken;}tokendata.getString(token);if(StringUtils.isNotBlank(token)){returntoken;}}returnnull;}catch(Exceptione){// 解析失败返回原始文本returnresponseText.trim();}}问题重复代码多每个字段都要写一遍if (StringUtils.isNotBlank(token))嵌套层次深if-else 套了 4 层可读性差扩展困难如果要支持新字段名需要复制粘贴更多 if维护痛苦逻辑分散容易漏改✅ 优雅方案Utils 实现privateStringparseToken(StringresponseText){if(StringUtils.isBlank(responseText)){returnnull;}try{JSONObjectjsonJSON.parseObject(responseText);// 第一步从根节点查找StringvaluefirstNotBlank(json.getString(access_token),json.getString(accessToken),json.getString(token));if(StringUtils.isNotBlank(value)){returnvalue;}// 第二步从 data 嵌套对象中查找JSONObjectdatajson.getJSONObject(data);returndatanull?null:firstNotBlank(data.getString(access_token),data.getString(accessToken),data.getString(token));}catch(Exceptionignored){returnresponseText.trim();}}// 核心工具方法返回第一个非空字符串privateStringfirstNotBlank(String...values){for(Stringvalue:values){if(StringUtils.isNotBlank(value)){returnvalue;}}returnnull;}巧妙之处赏析1️⃣ 可变参数 循环消除重复代码privateStringfirstNotBlank(String...values){for(Stringvalue:values){if(StringUtils.isNotBlank(value)){returnvalue;// 找到第一个非空就返回}}returnnull;}妙处一行顶六行用 5 行代码替代了 6 个 if-else 分支语义清晰方法名firstNotBlank直接表达了意图易于扩展新增字段只需在调用处加一个参数对比// 丑陋写法6 行 × 3 次 18 行if(StringUtils.isNotBlank(a))returna;if(StringUtils.isNotBlank(b))returnb;if(StringUtils.isNotBlank(c))returnc;// 优雅写法1 行returnfirstNotBlank(a,b,c);2️⃣ 分层查找逻辑清晰// 第一层根节点StringvaluefirstNotBlank(json.getString(access_token),json.getString(accessToken),json.getString(token));if(StringUtils.isNotBlank(value)){returnvalue;// 找到就返回}// 第二层data 嵌套对象JSONObjectdatajson.getJSONObject(data);returndatanull?null:firstNotBlank(data.getString(access_token),data.getString(accessToken),data.getString(token));妙处职责分离每一层只负责自己的查找逻辑短路优化第一层找到就直接返回不会执行第二层三元表达式data null ? null : ...简洁处理空指针3️⃣ 容错设计异常兜底try{// 尝试解析 JSONJSONObjectjsonJSON.parseObject(responseText);// ... 提取逻辑}catch(Exceptionignored){// 解析失败返回原始文本可能是纯文本 TokenreturnresponseText.trim();}妙处兼容性强支持 JSON 和纯文本两种格式永不崩溃即使解析失败也能返回可用结果静默降级不影响主流程典型场景// 场景1标准 JSON 响应{access_token:eyJhbG...}// 场景2纯文本响应eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...设计模式解读策略模式的简化版这段代码本质上是一个简化的策略模式策略1: 从根节点找 access_token/accessToken/token ↓ 失败 策略2: 从 data 节点找 access_token/accessToken/token ↓ 失败 策略3: 返回原始文本兜底与传统策略模式的区别❌ 传统需要定义接口、多个实现类、工厂方法✅ 简化用方法调用链 短路逻辑实现责任链模式的影子firstNotBlank(a, b, c) → 检查 a非空则返回 → 检查 b非空则返回 → 检查 c非空则返回 → 都为空返回 null这实际上是一个微型的责任链每个参数依次尝试直到成功。扩展性演示需求1支持新的字段名jwt_token丑陋写法需要加 2 个 if 分支根节点 data 节点// 根节点tokenjson.getString(jwt_token);if(StringUtils.isNotBlank(token)){returntoken;}// data 节点tokendata.getString(jwt_token);if(StringUtils.isNotBlank(token)){returntoken;}优雅写法只需在调用处加一个参数StringvaluefirstNotBlank(json.getString(access_token),json.getString(accessToken),json.getString(token),json.getString(jwt_token)// ← 新增这一行);需求2支持更深的嵌套层级data.result.token优雅写法继续分层// 第一层根节点StringvaluefirstNotBlank(...);if(StringUtils.isNotBlank(value))returnvalue;// 第二层data 节点JSONObjectdatajson.getJSONObject(data);if(data!null){valuefirstNotBlank(...);if(StringUtils.isNotBlank(value))returnvalue;// 第三层data.result 节点JSONObjectresultdata.getJSONObject(result);if(result!null){returnfirstNotBlank(result.getString(access_token),result.getString(accessToken),result.getString(token));}}returnnull;关键每一层的逻辑保持一致都是firstNotBlank(...)易于理解和维护。性能分析时间复杂度操作复杂度说明firstNotBlank(a, b, c)O(1)最多检查 3 个值json.getString()O(1)HashMap 查找整体逻辑O(1)固定次数的查找结论性能优异无循环遍历大集合。内存占用// 只创建了少量临时对象JSONObjectjsonJSON.parseObject(responseText);// 1 个对象JSONObjectdatajson.getJSONObject(data);// 可能 1 个对象对比丑陋写法内存占用相同但代码行数减少 60%。最佳实践总结✅ 值得学习的技巧提取通用工具方法privateStringfirstNotBlank(String...values){...}可复用到其他场景单元测试容易编写使用可变参数简化调用firstNotBlank(a,b,c,d,e)// 灵活传入任意数量参数分层查找 短路返回if(found)returnvalue;// 提前退出避免无效计算异常兜底保证健壮性catch(Exceptionignored){returnfallbackValue;// 优雅降级}⚠️ 改进建议1. 添加日志记录catch(Exceptione){log.warn(Token 响应解析失败返回原始文本: {},e.getMessage());returnresponseText.trim();}原因生产环境问题排查需要日志。2. 提取常量privatestaticfinalString[]TOKEN_FIELDS{access_token,accessToken,token};privateStringfindToken(JSONObjectjson){returnfirstNotBlank(json.getString(TOKEN_FIELDS[0]),json.getString(TOKEN_FIELDS[1]),json.getString(TOKEN_FIELDS[2]));}原因避免魔法字符串便于统一管理。3. 支持配置化// 从配置文件读取支持的字段名Value(${token.fields:access_token,accessToken,token})privateString[]tokenFields;privateStringfindToken(JSONObjectjson){String[]valuesArrays.stream(tokenFields).map(json::getString).toArray(String[]::new);returnfirstNotBlank(values);}原因不同环境可能需要不同的字段名。对比总结维度丑陋写法优雅写法代码行数~40 行~15 行嵌套层次4 层 if-else2 层逻辑可扩展性每加一个字段 6 行每加一个字段 1 参数可读性⭐⭐⭐⭐⭐⭐⭐可维护性⭐⭐⭐⭐⭐⭐⭐复用性无法复用firstNotBlank可复用结语这段代码的精髓在于用简单的抽象firstNotBlank消除重复用分层逻辑保持清晰用异常兜底保证健壮。它告诉我们优雅的代码不一定是高深的设计模式而是用最合适的方式解决实际问题。下次遇到类似的挨个尝试场景时记得提取通用方法使用可变参数分层 短路返回异常兜底这样写出来的代码既简洁又健壮