【问题标题】:Which "if" construct is faster - statement or ternary operator?哪个“if”构造更快 - 语句或三元运算符?
【发布时间】:2011-06-10 01:15:57
【问题描述】:

java 中有两种类型的 if 语句 - 经典:if {} else {} 和简写:exp ? value1 : value2。一个比另一个快还是一样?

声明:

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

三元运算符:

int x = (expression) ? 1 : 2;

【问题讨论】:

  • 我猜绝对没有区别。这只是语法。除非编译器有点邪恶(或其他),我错了
  • 你做了(微)基准测试吗?分享结果。
  • 两者都会被淘汰。根本不会有任何区别。并且不要费心反编译这些东西。 HotSpot 做的第一件事是去掉 javac 应用的所有优化。
  • 它们不存在于不同的速度。它们存在于不同的目的。我相信您了解语句和表达式之间的区别。语句执行操作。表达式产生值。 if 用于语句中。 ? 用于表达式。
  • +1,因为即使原始问题的意图被误导,对这个问题的回答也值得一读。

标签: java performance if-statement shorthand premature-optimization


【解决方案1】:

那里只有一种“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 是否出现在括号内(不像我之前的巨大缺陷尝试 :) 但我会非常如果 JITter 最终使用不同的本机代码,您会感到惊讶。

【讨论】:

  • s/条件语句/条件表达式/
  • 我猜你不是说mainmain2 完全相同?
  • 令人印象深刻。直到现在我才知道你可以编译字节码。
  • @Kyle:我编译了 Java,然后用 javap 反编译。
  • @Kyle:没错。我主要期望字节码是相同的。事实上,它只是几乎相同 :)
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    这些都是一样的。它们都相当快,通常在 10-30 纳秒左右。 (取决于使用模式)这个时间范围对您来说重要吗?

    你应该做你认为最清楚的事情。

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

      • 实践中的一个很好的例子:在Java中,如果我必须根据表达式的结果制作一个String final,我可以使用三元语法final String whichTable = (Integer.parseInt(clientId ) > 500) ? "serverClients" : "offlineClients";然后我可以在 whichTable 需要为 final 的地方使用表达式的值。以下是非法的: final String whichTable = ""; if (Integer.parseInt(clientId) > 500) { whichTable = "serverClients"; } else { whichTable = "offlineClients"; }
      • @JamesPerih 在 final 字段的情况下,您可以使用构造函数块来设置一个值(尽管条件运算符看起来比 IMO 好十亿倍),并且使用局部变量,您可以分配稍后在您所在的代码块中首次使用之前的值。我认为三元组比if-else 具有优势的唯一情况是在构造函数中调用super(...)this(...)
      【解决方案5】:

      两者都不 - 它们将被编译为相同的。

      【讨论】:

        【解决方案6】:

        三元运算符比 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:

        if-else 的时间:63

        三元时间:31

        Trail-2:

        if-else 的时间:78

        三元时间:47

        Trail-3:

        if-else 的时间:94

        三元时间:31

        Trail-4:

        if-else 的时间:78

        三元时间:47

        【讨论】:

        • 我在运行您的示例时得到了完全相反的结果,这表明结果不可靠。不幸的是,您陷入了微基准测试的陷阱——众所周知,正确地进行微基准测试非常困难。您可以在此处查看几个示例:stackoverflow.com/questions/2842695/what-is-microbenchmarking
        • 您的特定示例至少存在以下问题:4 次试验还远远不够,您始终以相同的顺序运行测试(第一个 if-else,第二个三元),您没有预热运行测试等之前的 JVM。
        猜你喜欢
        • 2023-03-26
        • 2011-03-08
        • 1970-01-01
        • 2012-11-03
        • 2017-10-20
        • 2017-10-26
        • 2019-08-24
        • 2018-12-26
        • 1970-01-01
        相关资源
        最近更新 更多