哪种“if”结构更快——语句还是三元运算符?

89

在Java中有两种if语句 - 经典的:if {} else {}和简写的:exp ? value1 : value2。它们中的一种比另一种更快,还是它们相同?

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

三元运算符:

int x = (expression) ? 1 : 2;

36
我猜想其实并没有任何区别,只是语法不同而已。除非编译器有些问题(或者其他原因),否则我是错误的。 - sinelaw
4
你是否对其进行了微基准测试?分享一下结果。 - BalusC
3
两者都会被 JIT 编译。没有任何区别。不要试图反编译这些东西。HotSpot 做的第一件事是去掉 javac 应用的所有优化。 - Ivo Wetzel
12
它们不是为了不同的速度而存在,它们是为了不同的目的而存在。我相信您理解陈述和表达之间的差异。陈述执行操作。表达式产生值。if用于陈述。?用于表达式。 - Mike Dunlavey
3
即使原问题的意图有误导性,仍值得阅读此问题的回答,因为它们具有很高的参考价值。 - jball
显示剩余8条评论
6个回答

109

这里只有一种“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/条件语句/条件表达式/ - Laurence Gonsalves
1
我猜你的意思不是让mainmain2完全相同,对吗? - ColinD
令人印象深刻。我之前不知道你可以编译字节码。 - Kyle
2
@Kyle:我编译了Java代码,然后用javap反编译了它。 - Jon Skeet
哦哦...你反编译它来看看它编译了什么,以决定哪种风格表现最佳? - Kyle
1
@Kyle:没错。我本来期望字节码是完全相同的。但实际上,它只是几乎相同 :) - Jon Skeet

10

你的两个例子可能会编译成相同或几乎相同的字节码,因此性能上应该没有区别。

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


8

这两个是相同的。它们都非常快,通常在10-30纳秒左右(取决于使用模式)。这个时间范围对你很重要吗?

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


4

除了其他答案,我还想补充一点:

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


4
Java 中一个很好的例子是,如果我需要根据表达式的结果使一个字符窜变成 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"; } - James Perih
@JamesPerih 在final字段的情况下,您可以使用构造块来设置值(尽管条件运算符在我看来好看很多),而对于局部变量,则可以在您所在的代码块中稍后首次使用之前分配一个值。我认为三元运算符比if-else更有优势的唯一情况是在构造函数内调用super(...)this(...)时。 - Kröw

3

它们不会有任何区别 - 它们将被编译成相同的结果。


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()));
    }
}

测试结果:

测试1:

if-else所需时间:63

三目运算符所需时间:31

测试2:

if-else所需时间:78

三目运算符所需时间:47

测试3:

if-else所需时间:94

三目运算符所需时间:31

测试4:

if-else所需时间:78

三目运算符所需时间:47


1
当我运行你的示例时,结果完全相反,这表明结果是不可靠的。不幸的是,你陷入了微基准测试的陷阱 - 微基准测试通常很难正确执行。你可以在这里看到一些例子:https://dev59.com/anE85IYBdhLWcg3wUBoZ - Rogach
你的特定示例存在至少以下问题:4次试验远远不够,你总是以相同的顺序运行测试(首先if-else,其次三元运算符),你在运行测试之前没有预热JVM等。 - Rogach

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接