Java “多个”之间是否存在性能差异;如果;声明vs.“;如果是,如果不是;为了相互排斥的条件?

Java “多个”之间是否存在性能差异;如果;声明vs.“;如果是,如果不是;为了相互排斥的条件?,java,optimization,Java,Optimization,我很好奇Java是如何对具有互斥条件的多个“if”语句进行优化的,但我自己不知道如何分析它。这个问题基本上是这个问题的Java版本 我已经看到了if语句返回的答案,但这个问题是针对if语句的,这些语句具有互斥条件但不返回 1。多个if语句 if (x == 0) doSomething(); if (x == 2) doSomething(); if (x == 5) doSomething(); if (x == 0) doSomething(); else if (x == 2) doSo

我很好奇Java是如何对具有互斥条件的多个“if”语句进行优化的,但我自己不知道如何分析它。这个问题基本上是这个问题的Java版本

我已经看到了
if
语句返回
的答案,但这个问题是针对
if
语句的,这些语句具有互斥条件但不返回

1。多个if语句

if (x == 0) doSomething();
if (x == 2) doSomething();
if (x == 5) doSomething();
if (x == 0) doSomething();
else if (x == 2) doSomething();
else if (x == 5) doSomething();
if (x == 0) doSomething();
if (x == 2) doSomething();
if (x == 5) doSomething();
if (x == 0) doSomething();
else if (x == 2) doSomething();
else if (x == 5) doSomething();
2。链接的If-else语句

if (x == 0) doSomething();
if (x == 2) doSomething();
if (x == 5) doSomething();
if (x == 0) doSomething();
else if (x == 2) doSomething();
else if (x == 5) doSomething();
if (x == 0) doSomething();
if (x == 2) doSomething();
if (x == 5) doSomething();
if (x == 0) doSomething();
else if (x == 2) doSomething();
else if (x == 5) doSomething();
问题
#1和#2是否执行相同的后期编译?

(另外:如果是这样的话,Java可以优化多复杂的条件?

没有什么比传统的计时测试更好的了:

long total = 0;
long startTime;
long endTime;

for (int j = 0; j < 10; j++) {
    startTime = System.currentTimeMillis();

    for (int i = 0; i < 100000000; i++) {
        if (i % 3 == 0) total += 1;
        if (i % 3 == 1) total += 2;
        if (i % 3 == 2) total += 3;
    }

    endTime = System.currentTimeMillis();
    System.out.println("If only: " + (endTime - startTime));

    startTime = System.currentTimeMillis();

    for (int i = 0; i < 100000000; i++) {
        if (i % 3 == 0) total += 1;
        else if (i % 3 == 1) total += 2;
        else if (i % 3 == 2) total += 3;
    }

    endTime = System.currentTimeMillis();
    System.out.println("If-else: " + (endTime - startTime));
}
System.out.println(total);
正如我们所看到的,即使if条件明显相互排斥,if-else块的运行速度也明显加快。因为两个循环所用的时间长度不同,所以每个循环的编译代码必须不同。显然,编译器没有对此进行优化。JIT或CPU分支预测也不完全相同。仍然存在着巨大的差异

我的建议是:尽可能使用If-else

编辑:我还尝试交换两个循环,得到了相同的结果。如果不是,如果快得多


编辑2:我在整个测试中添加了for循环,以消除初始化或预热中的任何差异。结果是一样的。

尽管差别很小,但还是有差别的。关键问题是,该过程的任何步骤是否由足够聪明的软件完成,从而推断如果
x==0
,则
x==2
x==5
必须为假

在Java字节码级别,它们通常会产生不同的结果。没有义务要求编译器足够聪明来分析差异。(Eugene对相关问题的回答表明Sun的Java 12编译器确实足够聪明,在某些情况下可以为您进行优化)

即时编译器往往相当激进。他们更可能意识到代码只能流经三个分支中的一个,并对其进行优化。但这仍然是一个依赖工具的说法。Java语言本身将它们视为不同的

现在,实际上,这一点都不重要,除非你在做一个非常紧密的循环。优化中的#1规则是“配置文件,然后优化”。在至少99%的情况下,没有理由优化这些细节

具体来说,在您给出的示例中,即使编译器和JIT未能为您优化代码,性能成本也可以忽略不计。在“平均”CPU上,成功预测的分支大约是函数调用成本的十分之一,因此在这些分支上调用
doSomething()
的事实将使成本相形见绌。如果额外的调用导致一些额外的分支预测失误,您可能会看到更糟糕的影响,但没有什么比调用函数更昂贵的了

现在,假设
doSomething()
实际上是像
x+=1
这样的fast的占位符,那么您需要分析以确定它是否正确

因此,我的建议是根据正确的选项编写
if/if/if
if/else if/else if
。无论哪一个对您想要使用的逻辑类型最有意义,都是正确的答案。如果这是一个只使用一条路径的分支,我建议使用
else If
。如果这是一种情况,函数将来可能会执行许多分支,但恰好当前的分支列表是互斥的,请执行
If/If/If
,向读者传达预期的结果

然后是个人资料。总是个人资料。如果你发现这个函数是一个热点,那么考虑一下if语句是否昂贵。
另一方面,编译器很难证明他们可以将
if
转换为
else if
。它必须对x进行分析,以确定另一个线程是否可以修改它。如果它是一个局部变量,则没有其他线程可以修改它。但是,如果它是一个成员变量,则可能有另一个线程在<<代码>中I/If/if < /Cord>块中修改<代码> x <代码>,从而导致它采取两条路径。您可能知道没有其他人会像这样修改
x
,但是编译器在进行这样的优化之前必须证明它,或者至少证明它所写的内容与Java内存模型规则的实现是一致的。

让我告诉您条件运算符“if()”是如何工作的。当您编写if()语句时,它会检查您在这些“()”中提供的条件的真实性。如果条件失败,那么编译器将查找可在If()条件失败时使用的备用语句或代码块。现在,对于这个替代内容,我们使用“else”块

根据你的问题,答案很容易理解。这两方面都有很大的不同

1)。多个If语句

if (x == 0) doSomething();
if (x == 2) doSomething();
if (x == 5) doSomething();
if (x == 0) doSomething();
else if (x == 2) doSomething();
else if (x == 5) doSomething();
if (x == 0) doSomething();
if (x == 2) doSomething();
if (x == 5) doSomething();
if (x == 0) doSomething();
else if (x == 2) doSomething();
else if (x == 5) doSomething();
在上面的代码中,无论是否满足任何条件,编译器都将解析所有if语句。因为它们是单独使用的,没有任何替代零件

2)。链接的If-else语句

if (x == 0) doSomething();
if (x == 2) doSomething();
if (x == 5) doSomething();
if (x == 0) doSomething();
else if (x == 2) doSomething();
else if (x == 5) doSomething();
if (x == 0) doSomething();
if (x == 2) doSomething();
if (x == 5) doSomething();
if (x == 0) doSomething();
else if (x == 2) doSomething();
else if (x == 5) doSomething();
现在在上面的代码中有一个主条件检查器
(x==0)
,如果失败,那么还有其他替代方案,所以编译器将检查它们,直到找到满意的解决方案

性能问题

在第一种情况下,编译器必须检查每个条件,因为它们都是独立的,这可能需要更多的时间。但在第二种情况下,它将只编译“elseif”部分w