Java如何处理IF语句和效率
我只是好奇Java在Java如何处理IF语句和效率,java,if-statement,Java,If Statement,我只是好奇Java在if语句中是如何工作的。(注意:当我在下面说“组件”时,我指的是由语句检查的单个部分,例如a,b,c) 哪一个在计算方面更有效 if (a && b && c) { do stuff } 或 我之所以问这个问题,是因为Java在第一个版本中所做的事情很重要。它是检查语句中的每一项内容还是检查a,如果它是false,则取消检查语句的其余部分 如果是这种情况,那么将最有可能失败的组件作为语句中的第一个组件是有意义的 如果每次都检查整个语句,则更合
if
语句中是如何工作的。(注意:当我在下面说“组件”时,我指的是由语句检查的单个部分,例如a
,b
,c
)
哪一个在计算方面更有效
if (a && b && c) { do stuff }
或
我之所以问这个问题,是因为Java在第一个版本中所做的事情很重要。它是检查语句中的每一项内容还是检查a
,如果它是false
,则取消检查语句的其余部分
如果是这种情况,那么将最有可能失败的组件作为语句中的第一个组件是有意义的
如果每次都检查整个语句,则更合理的做法是将组件分成一组不同的语句,如第二个示例中所示。对于(a&&b&&c)
,条件“短路”,即一旦一个语句出现故障,其余语句将不进行计算
if (a && b && c) { do stuff }
但是,除非获得a
、b
和c
的成本很高,否则这可能是过早优化的情况
如果部分或全部都很贵,那么如果你真的这么做了
if(getA()&&getB()&&getC())…
然后,如果
getA()
失败,甚至不会调用其他方法。这些代码片段完全等效,并生成完全相同的字节码:
0: iload_1
1: ifeq 20 //a == false (0)
4: iload_2
5: ifeq 20 //b == false (0)
8: iload_3
9: ifeq 20 //c == false (0)
12: //do stuff
20: return
虽然解释不同,但代码生成器生成相同的输出。在第一种情况下,由于延迟求值,如果前一项为
false
,则不会求值后续项。在第二种情况下,如果不满足条件,则运行时不会更深。在Java中,&&
和|
保证短路:操作数从左到右求值,结果确定后立即停止求值
从:
&
运算符类似于&
(§15.22.2),但仅当其左侧操作数的值为true
时,才计算其右侧操作数(从左到右分组)
|
运算符类似于|
(§15.22.2),但仅当其左侧操作数的值为false时才计算其右侧操作数。它在语法上是左关联的(它从左到右分组)
这意味着您的问题中的两个代码片段完全相同。检查这类问题的最佳方法是查看 在这种情况下,您需要: 在运行时,首先计算左侧操作数表达式;如果结果的类型为布尔型,则应进行拆箱转换(§5.1.8);如果结果值为false,则条件and表达式的值为false,并且不计算右侧操作数表达式
if (a && b && c) { do stuff }
因此,否,在表达式a&&b&&c
中,如果a
求值为false
,则不计算b
和c
请注意,这不是if
语句行为的一部分,而是&
运算符行为的一部分。您可以在别处使用表达式看到相同的效果:
// Still won't evaluate b and c if a is false...
boolean x = a && b && c;
(值得注意的是,当您想查阅规范时,语言的哪一部分会导致什么行为。)在第一种情况下,如果
在第一次遇到错误
情况(短路)时,if
的计算结果为错误
。否则,您将无法执行以下操作:
if(a != null && a.toString().equals("b"))
如果第二部分也将被评估,则不获取NullPointerException
if (a && b && c) { do stuff }
那有短路<如果a
的计算结果为false,则代码>&&将短路,这意味着未完成其余检查
除此之外,我认为这两种方法没有区别。这是:
if (condition is met) {
//continute to next check
if (condition is met) {
//continue to next check
if (condition is met) {
do stuff }
}
}
与:if(a&&b&&c){do stuff}
相同,但会占用大量空间。您实际上不必担心这个特定代码段的效率,因此使用第一个选项是最佳选择。你也可以这样做
if (a && b){
if (condition is met) {
do stuff }
}
&&和| |是短路逻辑运算符。这意味着在您的示例中,如果a为false,则表达式的其余部分将不会被计算
if (a && b && c) { do stuff }
如果需要非短路逻辑运算符,可以使用&和|
如果需要确认,可以查看Java语言规范的以下语句:我很好奇编译器会如何处理这两种情况,因此我使用Java 1.6编译了以下代码:
public class IfTest
{
public static void main(String[] args)
{
IfTest iffy = new IfTest();
iffy.doit();
}
private void doit()
{
Random rand = new Random();
boolean a = rand.nextBoolean();
boolean b = rand.nextBoolean();
boolean c = rand.nextBoolean();
if (a && b && c)
{
System.out.println("block 1");
}
if (a)
{
if (b)
{
if (c)
{
System.out.println("block 2");
}
}
}
}
}
…然后使用进行反编译。下面是反编译器从类文件生成的内容:
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: IfTest.java
import java.util.Random;
public class IfTest
{
public IfTest()
{
}
public static void main(String args[])
{
IfTest iffy = new IfTest();
iffy.doit();
}
private void doit()
{
Random rand = new Random();
boolean a = rand.nextBoolean();
boolean b = rand.nextBoolean();
boolean c = rand.nextBoolean();
if(a && b && c)
System.out.println("block 1");
if(a && b && c)
System.out.println("block 2");
}
}
我想你用哪种方式写并不重要。你可以自己很容易地尝试一下。我想通过制作a、b和c函数,这些函数在被调用时会打印出来,对吧?@Howard:我是一个极力主张尝试的人。然而,我不认为运行一些代码(甚至查看字节码)是确定短路行为是否得到保证的好方法。对于这一点,Java语言规范是决定性的资源?true意味着还必须对b进行评估-这是和,而不是OR@Tudor:没错。true应与
|
一起使用。谢谢。很有帮助,我没有考虑过那种特殊情况。很好的例子。所以你基本上是说这不重要?(除了在代码可读性方面)@Chro:是的,在性能方面并不重要。但是,如果计算例如<代码> A/COD>是费时的,考虑把它推得更远(或者更深),这样它就更有可能永远不会被评估。