&&能防止空指针或越界访问,因为它是短路运算符:左操作数为false时右表达式不执行,从而天然避免非法调用;而&无短路特性且易混淆类型,java强制其语义保证,go/js同理依赖该机制保障安全。

为什么 && 能防止空指针或越界访问
因为 && 是短路运算符:左边为 false 时,右边表达式根本不会执行。这让你能把“前提检查”和“后续操作”串在一条表达式里,天然形成保护屏障。
常见错误是用 &(按位与)代替 &&,比如 obj != null & obj.getName()——哪怕 obj 是 null,obj.getName() 仍会调用,直接抛 NullPointerException。
-
&&只接受boolean类型操作数,类型安全;&虽然也能用于boolean,但不短路,且容易和整数位运算混淆 - Java 编译器对
&&的短路行为有强制语义保证,不是优化技巧,而是语言契约 - Go 和 JavaScript 同样依赖该特性做安全访问,但 Go 更严格:不支持隐式转换,
s != nil && s[0]中若s为nil,s[0]绝对不执行
怎么写才算“安全的前置条件检查”
关键不是“能不能写成一行”,而是“条件是否可读、副作用是否可控、失败路径是否明确”。把判断逻辑具名化后,再用 && 连接,比堆砌长表达式更可靠。
- ✅ 推荐:
user != null && user.isActive() && user.hasPermission("EDIT")—— 每个环节都可独立调试,且天然短路 - ❌ 避免:
user != null && user.getProfile() != null && user.getProfile().getAvatarUrl() != null && !user.getProfile().getAvatarUrl().isEmpty()—— 过深嵌套,可读性差,建议拆成方法或提前返回 - ⚠️ 注意:
&&右侧不能有必须执行的副作用(如日志、计数、状态变更),否则可能被跳过。真需要两边都执行,就用&或显式分步
Java 里 boolean 局部变量未初始化的坑
Java 要求所有局部 boolean 变量必须显式赋值,否则编译报错。这个限制看似麻烦,实则帮你避开“未定义行为”的隐患。
- 错误写法:
boolean canAccess; if (user != null) canAccess = user.isAdmin(); if (canAccess) { ... }——canAccess在user == null时未初始化,编译失败 - 正确写法:
boolean canAccess = user != null && user.isAdmin();—— 一行完成判断与赋值,语义清晰,无未定义风险 - 如果条件复杂,优先封装为
isXxx()方法,而不是靠多个&&堆叠。例如:if (canEditDocument(user, doc)) { ... }
短路不是万能的,边界情况要手动兜底
&& 解决的是“执行顺序”问题,不是“逻辑完备性”问题。它不会帮你处理 null 以外的异常输入,也不会自动补默认值。
- 比如
list != null && !list.isEmpty() && list.get(0) > 0安全,但若list是LinkedList且极大,list.get(0)虽快,list.isEmpty()却仍是必要前置——别省略明显检查 - 数据库查询结果为
null或空集合?&&不管这些业务语义,只管执行流。该用Optional或判空就判空 - 最易忽略的一点:短路只看布尔值,不看异常。若左侧表达式本身抛异常(如
user.getRole()抛RuntimeException),&&根本没机会生效










