【问题标题】:Does nesting if statements improve performance or have other advantages over flat if statements?嵌套 if 语句是否会提高性能或与扁平 if 语句相比有其他优势?
【发布时间】:2015-01-30 14:06:51
【问题描述】:

我有一系列略显笨拙的 if 语句,我习惯性地嵌套如下:

// Cannot collide with right
    if(direction.x < 0)
    {
        // Cannot collide with top
        if(direction.y < 0)
        {
            // Check left and bottom
        }
        // Cannot collide with bottom
        else if (direction.y > 0)
        {
            // Check left and top
        }
        // Cannot collide with top or bottom
        else
        {
            // Check left only

        }
    }
    // Cannot collide with left
    else if (direction.x > 0)
    {
        // Cannot collide with top
        if(direction.y < 0)
        {
            // Check right and bottom
        }
        // Cannot collide with bottom
        else if (direction.y > 0)
        {
            // Check right and top
        }
        // Cannot collide with top or bottom
        else
        {
            // Check right only

        }
    }

但是我发现它有点难以阅读,并认为它可能更容易理解为一组扁平的 if 语句,有点像 switch:

// Cannot collide with right or top
    if(direction.x < 0 && direction.y < 0)
    {
        // Check left and bottom
    }
    // Cannot collide with right or bottom
    else if(direction.x < 0 && direction.y > 0)
    {
        // Check left and top
    }
    // Cannot collide with right, top or bottom
    else if(direction.x < 0)
    {
        // Check left only
    }
    // Cannot collide with left or top
    else if (direction.x > 0 && direction.y < 0)
    {
        // Check right and bottom
    }
    // Cannot collide with left or bottom
    else if (direction.x > 0 && direction.y > 0)
    {
        // Check right and top
    }
    // Cannot collide with left, top or bottom
    else
    {
        // Check right only
    }

这样做的明显缺点是我要多次重新检查一个条件。在这种情况下,它是如此之小,我无法想象它有什么不同,但我的问题是:

  1. 用于 C#、Java 等的现代编译器是否可以优化第二个示例以删除重复检查? 在此示例中这很好,但如果条件检查也有副作用,则可能会导致问题。
  2. 一般来说,哪种方法更受欢迎?

【问题讨论】:

  • 你的第二个例子并没有以任何方式展平,如果添加一个新的嵌套层,因为它相当于else { if(predicate) { ...,你就不需要{
  • 我认为单独阅读您的代码 cmets 表明应该首选哪种方式
  • 最好尽可能避免嵌套 if 语句。当我们有深层嵌套的 if 语句时,代码变得难以阅读。不建议使用 PMD 工具。

标签: java c# if-statement optimization compilation


【解决方案1】:

AND语句将被C#中的编译器快捷方式,因此如果direction.x 0"。

【讨论】:

  • 除非direction.x 被声明为volatile
【解决方案2】:

过早的优化是邪恶的。

在可读性方面我会做类似的事情

[Flags]
enum Direction
{
    None = 0,
    Top = 1 << 0,
    Bottom = 1 << 1,
    Left = 1 << 2,
    Right = 1 << 3,
}

然后

var d = (x > 0 ? Direction.Right : (x < 0 ? Direction.Left : Direction.None)) |
    (y > 0 ? Direction.Top : (y < 0 ? Direction.Bottom : Direction.None));
switch(d)
{
    case Direction.Left:
        ...
        break;
    case Direction.Right | Direction.Bottom:
        ...
        break;
    ...
}

【讨论】:

    【解决方案3】:

    我倾向于第一种方法,因为它减少了代码重复(除此之外它可能会稍微快一些 - 如果是 volatile 属性,则必须重新读取变量)。

    如果您需要将 direction.x &lt; 0 条件更改为 direction.x &gt; 1 会发生什么(这里可能不是最好的例子,但您明白了......)?您只需在一个处进行更改。

    另外,我认为第一种方法更容易理解:当您按照代码进行操作时,您知道如果您在 if 语句的第一个分支中,则在使用第二种方法时它“不能与右侧发生冲突”您总是必须考虑整个条件,并且还要考虑之前if 语句的所有条件,才能知道您是否到达那里。

    改进

    可以通过将条件与您想要制作的实际代码分开来改进您的代码,将其真正变成switch

    为此,我们将使用以下常量:

    static final int LEFT   = 0x01;
    static final int RIGHT  = 0x02;
    static final int TOP    = 0x10;
    static final int BOTTOM = 0x20;
    

    还有代码:

    final int dir = (d.x < 0 ? LEFT : d.x > 0 ? RIGHT  : 0)
                  + (d.y < 0 ? TOP  : d.y > 0 ? BOTTOM : 0);
    
    switch (dir) {
    case LEFT:           // Check left only
        break;
    case RIGHT:          // Check right only
        break;
    case LEFT + TOP:     // Check left and top
        break;
    case LEFT + BOTTOM:  // Check left and bottom
        break;
    case RIGHT + TOP:    // Check right and top
        break;
    case RIGHT + BOTTOM: // Check right and bottom
        break;
    }
    

    【讨论】:

      猜你喜欢
      • 2017-10-18
      • 1970-01-01
      • 2013-09-01
      • 2021-02-23
      • 1970-01-01
      • 2021-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多