【问题标题】:Java Compiler: Optimization of "cascaded" ifs and best practices?Java 编译器:“级联”ifs 和最佳实践的优化?
【发布时间】:2010-05-19 20:02:58
【问题描述】:

Java 编译器是否优化这样的语句

if (a == true) {
 if (b == true) {
  if (c == true) {
   if(d == true) {
       //code to process stands here
   }
  }
 }
}

if (a == true && b==true && c==true && d == true)

这是我的第一个问题:两者都采用完全相同的“CPU 周期”还是第一个变体“更慢”。

我的第二个问题是,如果被认为是糟糕的编程风格,那么第一个带有级联的变体是否如此冗长?

(我喜欢第一个变体,因为我可以更好地对我的表达式进行逻辑分组并更好地对其进行注释(我的 if 语句比示例中的更复杂),但这可能是糟糕的编程风格?)甚至更慢,这就是我的原因问...

谢谢 延斯

【问题讨论】:

标签: java optimization


【解决方案1】:

首先不要使用a == TRUE

 if (a) { ... }

其次是这样的代码:

public class Test {
  public int f(boolean a, boolean b, boolean c, boolean d) {
    if (a && b && c && d) {
      return 1;
    } else {
      return 2;
    }
  }

  public int g(boolean a, boolean b, boolean c, boolean d) {
    if (a)
      if (b)
        if (c)
          if (d)
            return 1;
    return 2;
  }
}

编译成(javap -c Test):

public class Test extends java.lang.Object{
public Test();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public int f(boolean, boolean, boolean, boolean);
  Code:
   0:   iload_1
   1:   ifeq    19
   4:   iload_2
   5:   ifeq    19
   8:   iload_3
   9:   ifeq    19
   12:  iload   4
   14:  ifeq    19
   17:  iconst_1
   18:  ireturn
   19:  iconst_2
   20:  ireturn

public int g(boolean, boolean, boolean, boolean);
  Code:
   0:   iload_1
   1:   ifeq    19
   4:   iload_2
   5:   ifeq    19
   8:   iload_3
   9:   ifeq    19
   12:  iload   4
   14:  ifeq    19
   17:  iconst_1
   18:  ireturn
   19:  iconst_2
   20:  ireturn

}

如您所见,字节码是相同的。

第三 - 这取决于问题,但通常过于冗长。如果您对此类细节发表评论:

  • 您的 cmets 太冗长了。 Thay 应该支持代码而不是重复它 (BAD: x = x + 1; // Increase x by 1) - 可能汇编程序是唯一的例外,因为 add rax, 1 ; Increase x by 1 通知 raxx
  • 您的代码正在做它可能不应该做的真正“聪明”的事情(但在某些情况下是合理的)

【讨论】:

  • 我不确定我是否同意“不要使用 x==true”。我的经验是,略读代码时它比标识符和!标识符之间的区别更具可读性。
  • 可能不应该有 x。阅读if (finished) System.exit(0)。用英文大声“如果完成退出”。阅读if (finished == true) System.exit(0)。 “如果完成是真正的退出”。通常您使用 1. 长描述性名称和 2. 仅在条件中使用布尔值。
  • @MP 一个完美的答案。我唯一要补充的是,人们通常可以使用多态性来替换长长的条件列表,这将使整个事情更容易测试。
  • @CD “一个完美的答案。” -> 不完全是。即使字节码不相同,JIT 也可以将其优化为相同的指令——我忘了​​提及它。但是,由于它是相同的,因此必须针对相同的指令进行优化。
  • 我完全同意不使用 if (a==true)
【解决方案2】:

Java“编译器”可能不会在这里进行任何优化(编译两者,然后反编译它们以进行比较)。但是 JVM 运行时可能会很好地做到这一点。

但是,也就是说,这是一个微优化;代码,以便下一个开发人员最容易理解您的代码。

这里的最佳实践是最易读的代码。

当然,不要使用(xxx == true),这是一种可怕的做法,而是使用(xxx)

【讨论】:

    【解决方案3】:

    根据文档,&amp;&amp;|| 运算符表现出“短路”行为,并且仅在需要时进行评估,因此两种方式的 CPU 周期应该相同。

    && 和 ||运营商执行 条件与和条件或 对两个布尔表达式的操作。 这些运营商展示 “短路”行为,其中 表示第二个操作数是 仅在需要时进行评估。

    有关详细信息,请参阅

    【讨论】:

      【解决方案4】:

      第一个变体可以更轻松地在一个或您的条件上放置断点,并且在检查您的条件时抛出的任何异常的堆栈跟踪也将指示正在检查哪一行。

      【讨论】:

      • 恕我直言,如果 coditions 改变了状态(尤其是不在单独的函数中)[1],这是蜜蜂“太聪明”的一些迹象。因此,要么将它们导出到其他函数,您可以中断它们,或者您可以在每个分支中的条件之后中断(或按下一步)并检查结果。 [1] 异常可能是检查非错误失败。
      【解决方案5】:

      这不是优化。这两个版本是完全等价的。两者都跑得更快。

      【讨论】:

        猜你喜欢
        • 2011-03-14
        • 2022-08-16
        • 1970-01-01
        • 2020-11-07
        • 2023-03-28
        • 1970-01-01
        • 1970-01-01
        • 2023-03-28
        • 2011-04-07
        相关资源
        最近更新 更多