我一直在阅读我使用的 API 实现的源代码,并偶然发现了这部分代码:
if (condition1 & condition2 && (condition3 || condition4))
条件 1 和 2 不调用任何方法或执行任何操作,而条件 3 和 4 会。我想知道为什么程序员决定不使用短路 && 运算符来比较前两个语句,因为我看不到使用它的任何好处(要检查的另一个条件,另外两个条件实际上可能对其他语句有任何影响部分程序仍处于短路状态)。
我一直在阅读我使用的 API 实现的源代码,并偶然发现了这部分代码:
if (condition1 & condition2 && (condition3 || condition4))
条件 1 和 2 不调用任何方法或执行任何操作,而条件 3 和 4 会。我想知道为什么程序员决定不使用短路 && 运算符来比较前两个语句,因为我看不到使用它的任何好处(要检查的另一个条件,另外两个条件实际上可能对其他语句有任何影响部分程序仍处于短路状态)。
我能想到的这样做的唯一原因是避免与&&
. 您可以在字节码中看到这一点:
a & b
:
ILOAD 1
ILOAD 2
IAND
a && b
:
ILOAD 1
IFEQ L3
ILOAD 2
IFEQ L3
ICONST_1
GOTO L4
当然,在某些情况下,结果可能会&
略微优于其他情况&&
(特别是,当您几乎可以肯定第一个条件为真时)。尽管如此,&&
通常还是首选,因为 1) 这种情况很少见,2) 在大多数情况下,性能差异完全可以忽略不计。
在不知道多久condition1
为真的情况下,使用 会更好(效率稍高一些)&&
,因为condition2
不需要检查第二个操作数是否condition1
为假,这样可以节省一些 CPU 指令。
如果统计condition1
上经常是正确的,那么使用它可能更有效&
,因为(通常不必要的)短路检查将被跳过。
在java中,您可以使用按位和布尔操作数来给出布尔结果,但唯一一次使用和&
之间存在功能差异是如果在第二个操作数中调用代码,例如:&
&&
condition1 & <some code giving a boolean> // exdcutes "some code" regardless of condition1
condition1 && <some code giving a boolean> // only executes "some code" if condition1 is true
我会考虑使用&
to 总是运行<some code giving a boolean>
在“副作用”领域,不值得它引起的混乱。
考虑到已经讨论过的一点,如果条件是布尔值,& 也一样快,实际上有一个原因是 & 运算符可能比 && 更受欢迎。
在 Java 语言规范中,§15.7。
Java 编程语言保证运算符的操作数看起来是以特定的评估顺序进行评估的,即从左到右。
建议代码不要严重依赖本规范。当每个表达式最多包含一个副作用时,代码通常会更清晰,作为其最外层的操作,并且当代码不完全依赖于表达式的从左到右求值的结果出现的异常时。
如果您检查操作顺序,您会看到 & 在 && 之前。因此,这个陈述坚持了明确评估顺序的原则,而不依赖于Java从左到右的评估。如果条件 3 或条件 4 调用修改方法,这个选择将特别重要——尽管这将是糟糕的编码。