短路与(&&)和短路或(||)的核心区别在于:前者左操作数为false时跳过右表达式,后者左操作数为true时跳过右表达式;而&和|无论左值如何均强制执行两边,且&&/||仅支持布尔类型,&/|还可用于整数位运算。

短路与(&&)和短路或(||)的核心区别,在于是否“跳过右侧表达式”——这不是语法糖,而是编译器生成的跳转指令级行为。普通逻辑运算符(&、|)则强制执行两边,没有条件跳转。
执行流程:从左到右,但“停不停”由结果决定
Java 虚拟机在处理 && 时,实际插入的是条件跳转字节码(如 ifne 或 ifeq):
- 先计算左操作数;若为 false,直接跳到整个表达式结束位置,右侧代码块完全不进栈、不求值;
- 仅当左操作数为 true,才继续压栈、计算右操作数。
而 & 对应的是连续求值指令(如 iand 前的两次 iload),左右两边无论真假都必定执行——哪怕左边已是 false,右边仍会完成加载、调用、自增等全部动作。
副作用是否触发,是肉眼可见的分水岭
副作用(如方法调用、变量修改、IO 操作)是否发生,直接暴露底层差异:
-
obj != null && obj.getName():obj 为 null 时,getName()根本不进方法栈,不会抛 NPE; -
obj != null & obj.getName():即使 obj 是 null,getName()仍会被调用,运行时报错; -
flag || logError():flag 为 true,logError() 不执行,日志不写; -
flag | logError():logError() 总会执行,哪怕 flag 已经确保结果为 true。
类型系统限制反映设计意图
底层执行机制也约束了语法边界:
- && 和 || 只接受布尔类型——因为它们服务于逻辑判定流程,JVM 要求两侧能明确归为 true/false;
- & 和 | 可用于整数(位运算)或布尔(非短路逻辑),编译器靠操作数类型自动切换语义;
- 试图写
5 && 3会编译失败,不是性能问题,而是类型系统拒绝把整数塞进逻辑跳转路径。
真实场景中的指令开销差异
在字节码层面,短路运算多出 1–2 条分支指令,但换来的是右侧整段逻辑的彻底省略:
- 右侧是简单变量(如
isValid字段):短路优势微弱,但安全; - 右侧含方法调用(如
db.query().size() > 0):短路可避免一次数据库 round-trip; - 右侧含自增(如
i++ > 5):短路让 i 保持原值,非短路则必然修改——这已不是性能问题,而是逻辑正确性问题。











