【问题标题】:What is better: multiple "if" statements or one "if" with multiple conditions?哪个更好:多个“if”语句或一个带有多个条件的“if”?
【发布时间】:2011-07-12 17:01:32
【问题描述】:

对于我的工作,我必须开发一个小型 Java 应用程序来解析非常大的 XML 文件(约 30 万行)以选择非常具体的数据(使用 Pattern),所以我正在尝试对其进行一些优化。我想知道这 2 个 sn-ps 之间哪个更好:

if (boolean_condition && matcher.find(string)) {
    ...
}

或

if (boolean_condition) {
    if (matcher.find(string)) {
        ...
    }
}

其他细节:

  • 这些 if 语句在循环内的每次迭代中执行(约 20k 次迭代)
  • boolean_condition 是使用外部函数在每次迭代中计算得到的 boolean
  • 如果boolean 设置为false,我不需要测试正则表达式是否匹配

感谢您的帮助。

【问题讨论】:

  • 没有简单的答案。查看this SO discussion关于同一主题的信息。
  • 没有任何性能差异。这纯粹是一个风格问题,这使它成为一个见仁见智的问题。

标签: java optimization if-statement multiple-conditions


【解决方案1】:

我遵循的一条黄金法则是尽可能“避免嵌套”。但如果它的代价是使我的单个 if 条件过于复杂,我不介意将它嵌套出来。

除了您使用的是短路&& 运算符。所以如果布尔值是假的,它甚至不会尝试匹配!

所以,

if (boolean_condition && matcher.find(string)) {
    ...
}

是要走的路!

【讨论】:

  • 谢谢!我不确定运算符是否设置为 false,匹配是否会执行。
  • 考虑if(x != null && x.isY());如果 && 没有 使评估短路,那会在 x == null 的瞬间炸毁你的脸。
  • 确实如此!但我必须确定,所以我问
  • +adarshr 好吧,即使在嵌套的 if 中,它也会短路,因为如果外部 if 评估为 false,那么它不会费心检查内部 if,如果第一个评估为false 会短路
  • @user 你不会在评估之前检查 null 吗?常识说是? ArgumentNullException 也许?
【解决方案2】:

第一个。如果像这样嵌套,我会尽量避免,我认为这是糟糕的样式/丑陋的代码,&& 会短路,并且只有在布尔值为真时才使用 matcher.find() 进行测试。

【讨论】:

    【解决方案3】:

    两种方式都可以,如果第一个条件为假,则不会测试第二个条件。

    使用使代码更具可读性和可理解性的代码。仅针对两个条件,第一种方式更具逻辑性和可读性。与&&、|| 和! 相关联的 5 或 6 个条件可能不再是这种情况。

    【讨论】:

      【解决方案4】:

      Java 对这些布尔运算符使用短路,因此这两种变体在功能上是相同的。因此,如果boolean_condition 为假,则不会继续匹配

      归根结底,你会发现它更易于阅读和调试,但如果你最终得到大量大括号,深度嵌套可能会变得笨拙

      如果条件变长,提高可读性的一种方法是简单地将其拆分为多行:

      if(boolean_condition &&
         matcher.find(string))
      {
          ...
      }
      

      此时唯一的选择是是否放 && 和 ||在上一行的末尾,或当前行的开头。

      【讨论】:

        【解决方案5】:

        以下两种方法:

        public void oneIf(boolean a, boolean b)
        {
            if (a && b)
            {   
            }
        }
        
        public void twoIfs(boolean a, boolean b)
        {
            if (a)
            {
                if (b)
                {       
                }
            }
        }
        

        为方法主体生成完全相同的字节码,因此不会有任何性能差异,这意味着它纯粹是您使用的风格问题(我个人更喜欢第一种风格)。

        【讨论】:

        • 我不会怀疑public void noIfs(boolean a, boolean b) {} 方法是否也产生了相同的字节码 ;-)
        • @Axel 不,它没有(我刚刚检查过!)这并不奇怪,Java 编译器几乎没有优化,让 JVM 在运行时完成。
        • 我认为解析器在第二个构造中还有更多工作要做,因为它必须确定下一条语句是'if'还是其他东西。另一方面,在第一个构造中,它只会解析条件,并且知道跟随是条件的一部分。
        【解决方案6】:

        在性能方面,它们是相同的。

        • 但即使他们不是

        几乎可以肯定,这段代码中占主导地位的是matcher.find(string),因为它是一个函数调用。

        【讨论】:

          【解决方案7】:

          我倾向于看到太多的 && 和 ||串在一起形成逻辑汤,通常是微妙错误的来源。

          添加另一个 && 或 || 太容易了到你认为正确的地方,打破现有的逻辑。

          因此,作为一般规则,我尽量不使用其中任何一个,以避免随着需求的变化而增加更多内容的诱惑。

          【讨论】:

            【解决方案8】:

            如果您希望遵守Sonar rule squid:S1066,您应该折叠 if 语句以避免警告,因为它声明:

            应合并可折叠的“if”语句

            【讨论】:

              【解决方案9】:

              我建议将您的表达式提取为具有语义意义的变量,然后将其传递给您的评估。而不是:

              if (boolean_condition && matcher.find(string)) { ... }
              

              将表达式分配给变量,然后计算变量:

              const hasItem = boolean_condition && matcher.find(string)
              
              if (hasItem) { ... }
              

              使用这种方法,即使是最复杂的评估也可以保持可读性:

              const hasItem = boolean_condition && matcher.find(string)
              
              const hasOtherThing = boolean_condition || boolean_condition
              
              const isBeforeToday = new Date(string) < new Date()
              
              if (hasItem && hasOtherThing && isBeforeToday) { ... }
              

              【讨论】:

                【解决方案10】:

                由于“&&”,大多数人更喜欢使用下面的那个。

                if (boolean_condition && matcher.find(string)) {
                ...
                }
                

                我们通常将这些称为“短路(或最低评估)”。这意味着只有当第一个参数没有足够的信息来确定表达式的值时,才会评估第二个参数(这里是“matcher.find(string)”)。例如,如果“boolean_condition”是false,那么整体条件一定是false(因为这里是逻辑AND 运算符)。然后编译器不会检查第二个参数,这将导致减少代码的运行时间。

                【讨论】:

                • 这不是已经包含在现有答案中了吗? (更重要的是——这可能在 2011 年被认为是热门话题,但在 2021 年,这个问题显然过于基于观点而不能成为话题,这意味着How to Answer 适用)。
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2019-12-23
                • 1970-01-01
                • 2013-12-17
                • 2021-10-08
                • 2014-10-20
                • 2017-09-25
                相关资源
                最近更新 更多