在循环中使用if语句的最优化方法是什么?

时间:2012-05-26 09:17:14

标签: java optimization if-statement

我有一个我需要处理的列表。这些项目已启用或已禁用。用户可以选择是否显示禁用的项目。

因此,cond2取决于项目,而cond1则取决于项目。这是我遇到的困境:我应该使用cond1 && !cond2还是!(!cond1 || cond2)?或者我应该在循环之前检查cond2(显示禁用的项目)?我还想(如我在代码中所见)我是否应该cond2放在cond1之前,因为cond2  是一个布尔变量,并且“短路”(延迟评估?),它会更快吗?

我主要担心的是速度。如果我在循环中有很多项目,这可能是一个重要的变化。

这是说明选项的代码:

// First Option
for (String item : items) {
    doSomethingFirst(item);
    if (isDisabled(item) && !showDisabled) {
        continue;
    }
    doSomethingElse(item);
}

// Second Option
for (String item : items) {
    doSomethingFirst(item);
    if (!(!isDisabled(item) || showDisabled)) {
        continue;
    }
    doSomethingElse(item);
}

// Third Option
if (showDisabled) {
    for (String item : items) {
        doSomethingFirst(item);
        doSomethingElse(item);
    }
} else {
    for (String item : items) {
        doSomethingFirst(item);
        if (isDisabled(item)) {
            continue;
        }
        doSomethingElse(item);
    }
}

那么,isDisabled(item)showDisabled的顺序是否重要?我应该在循环之前检查一下吗?或者编译器是否优化了? (我怀疑......)

PS 我不知道如何通过测量来查看实际值,如果相关,请执行此操作。

感谢。

5 个答案:

答案 0 :(得分:3)

在Java中,表达式从左到右进行计算。使用&&如果第一个条件为假,则不执行第二个条件,如果第一个条件为真,则使用||,第二个条件不执行。

因此,在您的案例中showDisabled尝试将可以更快解决的条件放在首位。

对于第三个例子,它看起来更好,因为你只检查一次布尔值,但我猜它并没有真正改变性能,bool比较并不是真的很贵。在代码的其他部分中,您可能会有更好的改进。 (对于可读的方面,它不是我最喜欢的 - 很长时间)

如果您想测量案例中的表现,请使用分析器。

或者添加您的代码:

long start=System.currentTimeMillis();
//code to analyse
long timeSpent = System.currentTimeMillis()-start

您必须将代码置于循环中,以使其相关。你可能会注意到Java会在一些循环之后提高性能;)。

答案 1 :(得分:2)

关于可读性,另一个好的做法是将函数和变量命名为正状态。阅读双重否定词很难。你还想读哪一个?

enabled

或者

!disabled

虽然以负面形式命名事物是有道理的,但有一些案例是有道理的。例如,如果您将它们用于终止条件,例如文件结束。 while(!feof(fp))

但在大多数情况下,常规应该是以正面形式命名,因此阅读代码的摩擦力较小。

让我们看看您的代码如何以正面形式呈现:

// First Option
for (String item : items) {
    doSomethingFirst(item);

    // if (isDisabled(item) && !showDisabled) {

    if (!isEnabled(item) && showEnabled) {
        continue;
    }
    doSomethingElse(item);
}

该代码的可读性肯定有所改善。

即使以下内容也变得可读,可以避免双重否定,阅读代码实际上只是阅读它,而不是过多地计算它。我曾经读过一篇文章,建议在编写代码时,阅读也应该非常愉快,他说阅读代码不应该像读一本侦探小说。阅读双重否定代码就像阅读和破译侦探小说一样。

// Second Option
for (String item : items) {
    doSomethingFirst(item);

    // if (!(!isDisabled(item) || showDisabled)) {

    // You can now avoid double negatives
    if (!( isEnabled(item) || !showEnabled )) {
        continue;
    }
    doSomethingElse(item);
}

事实上,以下不仅仅是双重否定,它是三重的:

if (!(!isDisabled(item)

  1. isDisabled
  2. !isDisabled
  3. !(​​!isDisabled
  4. 在您破译该代码的意图之前,需要进行两遍读取,甚至三遍读取

答案 2 :(得分:1)

与这些类型的问题一样,您应该对此进行衡量,以确定这本身是否是您的瓶颈。如果是,那么我会测量替代品。我怀疑上面的情况,它会使你的替代品几乎没有区别,特别是因为你可能会用列表条目做更重量级的事情(显示它们?将它们写入数据库或文件?)< / p>

衡量这一点的最简单方法是生成一个相当大的列表,在处理,处理然后记录所采用的ms(或秒)之前记录时间(例如,通过System.currentTimeMillis())。

答案 3 :(得分:1)

  

我应该使用cond1&amp;&amp; !cond2或!(!cond1 || cond2)?或者我应该在循环之前检查cond2(显示已禁用的项目)?

无论什么表达你的想法最好,即任何更具可读性。

  

我主要担心的是速度。

写作速度?重构速度?编译速度快?发展速度?阅读和理解速度?调试速度?执行速度?

你不能一次拥有所有。没有语言。

答案 4 :(得分:1)

我将选择选项1,然后反向切换

isDisabled(item) && !showDisabled

!showDisabled && isDisabled(item)

如果isDisabled(...)和你说的一样慢,最好首先测试更快的情况。 现在与其他选项相比,这是最明确和可读的:

  • 我们为所有项目做了一些事情
  • 我们跳过了验证某些测试的项目
  • 我们为所有其他项目做点什么。

很难做得更明确。第三种选择很简单。