就我而言,我使用的是 C#,但问题的概念也适用于 Java。希望答案足够通用以涵盖两种语言。否则最好把问题分成两部分。
我一直在想哪一个是更好的做法。
编译器是否负责增强“第二个”代码,使其性能与“第一个”代码一样好?
是否可以同时获得“更好的性能”和“优化”代码?
冗余/更好的性能代码:
string name = GetName(); // returned string could be empty
List<string> myListOfStrings = GetListOfStrings();
if(string.IsNullOrWhiteSpace(name)
{
foreach(string s in myListOfStrings)
Console.WriteLine(s);
}
else
{
foreach(string s in myListOfStrings)
Console.WriteLine(s + " (Name is: " + name);
}
string name = GetName(); // returned string could be empty
List<string> myListOfStrings = GetListOfStrings();
foreach(string s in myListOfStrings)
Console.WriteLine(string.IsNullOrWhiteSpace(name) ? s : s + " (Name is: " + name);
显然“第一个”代码的执行时间较短,因为它每个循环仅执行一次条件“string.IsNullOrWhiteSpace(name)”。而“第二个”代码(更好)在每次迭代时执行条件。
请考虑较长的循环执行时间而不是较短的循环执行时间,因为我知道当循环执行时间较短时,性能不会有差异。
不,不能。
布尔表达式也可能有副作用。 在这种情况下,它不会,但编译器无法知道这一点。 为了满足规范,执行此类副作用很重要,因此需要在每次迭代中执行检查。
因此,您需要问的下一个问题是,在这种情况下,执行您提到的优化是否“重要”? 在任何情况下,我都可以想象您所展示的确切代码,但可能不会。 检查速度非常快,几乎肯定不会成为瓶颈。 如果存在性能问题,几乎肯定会有更大的鱼。
MoveNext
的 IEnumerator
调用怎么办? 如果只执行一次很重要,因为您不希望副作用发生 N 次,那么这就是一个
重要的问题。
在这种情况下有几种可能的解决方案。
最简单的方法很可能只计算布尔表达式一次,然后将其存储在变量中:
bool someValue = ComputeComplexBooleanValue();
foreach(var item in collection)
{
if(someValue)
doStuff(item);
else
doOtherStuff(item);
}
如果你想执行布尔值0-1次(即,在集合为空的情况下避免调用它一次),那么我们可以使用
Lazy
来延迟计算该值,但确保它最多仍然只被计算一次:
var someValue = new Lazy<bool>(() => ComputeComplexBooleanValue());
foreach (var item in collection)
{
if (someValue.Value)
doStuff(item);
else
doOtherStuff(item);
}
您应该始终首先选择更容易理解和维护的方式。这意味着将重复代码减少到绝对最小值(DRY
)。此外,这种微观优化对于许多系统来说并不那么重要。另请注意,代码越短并不总是越好。
string name = GetName(); // returned string could be empty
bool nameIsEmpty = string.IsNullOrWhiteSpace(name);
foreach (string s in GetListOfStrings()) {
string messageAddition = "";
if (!nameIsEmpty) {
messageAddition = " (Name is: " + name + ")";
}
Console.WriteLine(s + messageAddition);
// more code which uses the computed value..
// otherwise the condition can be moved out the loop
}
我发现在方法调用中额外的
if
语句比
?:
运算符更容易阅读,但这可能是个人喜好。
如果您想稍后提高性能,您应该分析您的应用程序并首先开始优化最慢的代码部分。也许你的
GetListOfStrings()
方法太慢了,以至于其他代码的性能完全无关。如果您测量到重复循环可以显着提高性能,您可以考虑更改它。