哪种“如果”构造更快-语句还是三元运算符?


83

if在Java中,经典语句有两种:if {} else {}和速记:exp ? value1 : value2。一个比另一个快还是相同?

声明:

int x;
if (expression) {
  x = 1;
} else {
  x = 2;
}

三元运算符:

int x = (expression) ? 1 : 2;

34
我猜完全没有区别。这只是语法。除非编译器有些邪恶(或其他),并且我错了
sinelaw

4
您(微)基准了吗?分享结果。
BalusC

3
两者都会被激怒。完全没有区别。并且不要打扰反编译这些东西。HotSpot要做的第一件事是进行javac应用的所有优化。
伊沃·韦策尔

11
它们并不以不同的速度存在。它们出于不同的目的而存在。我确定您了解语句和表达式之间的区别。语句执行操作。表达式产生值。if用于语句中。?用于表达式中。
Mike Dunlavey

3
+1是对这个问题的回答,即使原始问题的意图有误,也值得一读。
jball 2011年

Answers:


106

那里只有一种“ if”语句。另一个是条件表达式。至于哪种性能更好:它们可以编译为相同的字节码,并且我希望它们的行为相同-或如此接近以至于您绝对不希望在性能方面选择一个。

有时一条if语句更具可读性,有时条件运算符将更具可读性。特别是,当两个操作数简单且无副作用时,我建议使用条件运算符,而如果两个分支的主要目的它们的副作用,则可能要使用一条if语句。

这是一个示例程序和字节码:

public class Test {
    public static void main(String[] args) {
        int x;
        if (args.length > 0) {
            x = 1;
        } else {
            x = 2;
        }
    }

    public static void main2(String[] args) {
        int x = (args.length > 0) ? 1 : 2;
    }
}

字节码反编译为javap -c Test

public class Test extends java.lang.Object {
  public Test();
    Code:
       0: aload_0
       1: invokespecial #1
       4: return

  public static void main(java.lang.String[]
    Code:
       0: aload_0
       1: arraylength
       2: ifle          10
       5: iconst_1
       6: istore_1
       7: goto          12
      10: iconst_2
      11: istore_1
      12: return

  public static void main2(java.lang.String[
    Code:
       0: aload_0
       1: arraylength
       2: ifle          9
       5: iconst_1
       6: goto          10
       9: iconst_2
      10: istore_1
      11: return
}

如您所见,这里的字节码略有不同-是否istore_1在brance中发生(与我之前的严重缺陷尝试不同:),但是如果JITter以不同的本机代码结束,我将感到非常惊讶。


s /条件语句/条件表达式/
Laurence Gonsalves

1
我猜你并不意味着您在mainmain2是完全一样的?
ColinD 2011年

令人印象深刻。我直到现在才知道您可以编译字节码。
凯尔

2
@Kyle:我编译了Java,然后用javap反编译了。
乔恩·斯基特

1
@Kyle:是的。我最希望字节码是相同的。实际上,它几乎是完全相同的:)
Jon Skeet

10

您的两个示例都可能会编译为相同或几乎相同的字节码,因此性能应该没有差异。

如果执行速度有所不同,则仍应使用最惯用的版本(第二个版本用于根据简单条件和两个简单​​的子表达式分配单个变量,第一个版本用于执行更复杂的操作或单行不适合的操作)。


8

这些都是一样的。两者都相当快,通常约为10到30纳秒。(取决于使用模式)这个时间范围对您来说重要吗?

您应该做自己认为最清楚的事情。


4

只是添加到所有其他答案:

第二个表达式通常称为三级/三级运算符/语句。它可以返回表达式,因此非常有用。有时,它使代码对于典型的简短语句更加清晰。


4
在实践中这是一个很好的例子:在Java中,如果我必须基于表达式的结果将String结尾,那么我可以使用三元语法final String whichTable =(Integer.parseInt(clientId)> 500)?“ serverClients”:“ offlineClients”; 然后,我可以在whichTable需要为最终值的地方使用表达式的值。以下内容将是非法的:final String whichTable =“”; 如果(Integer.parseInt(clientId)> 500){whichTable =“ serverClients”; } else {whichTable =“ offlineClients”; }
James Perih 2013年

@JamesPerih对于final字段,您可以使用构造函数块设置一个值(尽管条件运算符看起来比IMO好十亿倍),并且可以使用局部变量在稍后在代码块中首次使用之前分配一个值我认为,三元组比后者更具优势的唯一情况if-else是在调用时super(...)this(...)在构造函数内部时。
克鲁夫


0

三元运算符比if-else条件要快。

public class TerinaryTest {
    public static void main(String[] args)
    {
        int j = 2,i = 0;
        Date d1 = new Date();
        for(long l=1;l<100000000;l++)
            if(i==1) j=1;
                else j=0;
        Date d2 = new Date();
        for(long l=1;l<100000000;l++)
            j=i==1?1:0;
        Date d3 = new Date();
        System.out.println("Time for if-else: " + (d2.getTime()-d1.getTime()));
        System.out.println("Time for ternary: " + (d3.getTime()-d2.getTime()));
    }
}

测试结果:

Trail-1:

否则的时间:63

三元时间:31

Trail-2:

否则的时间:78

三级时间:47

Trail-3:

否则的时间:94

三元时间:31

Trail-4:

否则的时间:78

三级时间:47


运行示例时,我得到的结果恰好相反,这表明结果不可靠。不幸的是,您陷入了微基准测试陷阱-众所周知,正确进行微基准测试非常困难。几个例子,您可以在这里看到:stackoverflow.com/questions/2842695/what-is-microbenchmarking
Rogach

您的特定示例至少会遇到以下问题:4次试用是远远不够的,您始终以相同的顺序运行测试(第一个if-else,第二个三进制),没有在运行测试之前预热JVM,等等。
罗加奇
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.