0

我有一份需要处理的清单。这些项目被启用或禁用。用户可以选择是否显示禁用的项目。

所以你有cond2这取决于项目,cond1但事实并非如此。这是我陷入的两难境地:我应该使用cond1 && !cond2or!(!cond1 || cond2)吗?cond2或者我应该在循环之前检查(显示禁用的项目)?我还认为(正如您将在我放置的代码中看到的那样)如果我应该放置cond2before 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我不知道如何进行测量以查看实际值,如果相关,请执行。

谢谢。

4

5 回答 5

3

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

因此,在您的情况下,请尝试将可以更快解决的条件放在首位showDisabled

对于第三个示例,它看起来更好,因为您只检查了一次布尔值,但我想它并没有真正改变性能,布尔比较并不是真的很昂贵。您可能会对代码的其他部分进行更好的改进。(而且对于可读性而言,这不是我最喜欢的 - 很长)

例如,如果您想在您的案例中测量性能,请使用分析器。

或添加您的代码:

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

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

于 2012-05-26T09:24:23.497 回答
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. 被禁用
  2. !被禁用
  3. !(!被禁用

你需要读两遍,甚至三遍才能破译该代码的意图

于 2012-05-26T10:11:20.807 回答
1

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

最能表达您的想法的东西,即更具可读性的东西。

我主要关心的是速度。

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

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

于 2012-05-26T09:32:46.517 回答
1

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

isDisabled(item) && !showDisabled

!showDisabled && isDisabled(item)

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

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

很难做更明确的。第三个选项很丑陋。

于 2012-05-26T09:33:21.183 回答
1

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

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

于 2012-05-26T09:20:31.177 回答