我有一个我需要处理的列表。这些项目已启用或已禁用。用户可以选择是否显示禁用的项目。
因此,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 我不知道如何通过测量来查看实际值,如果相关,请执行此操作。
感谢。
答案 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)
在您破译该代码的意图之前,需要进行两遍读取,甚至三遍读取
答案 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(...)
和你说的一样慢,最好首先测试更快的情况。
现在与其他选项相比,这是最明确和可读的:
很难做得更明确。第三种选择很简单。