性能java编译器能否优化循环以尽早返回?
我正在与一家外部图书馆合作,该图书馆决定自行处理馆藏。不使用它或更新不在我的控制范围之内。要使用这个第三方“集合”的元素,它只返回迭代器
在代码审查期间,出现了一个关于在代码中有多个返回以获得性能的问题。我们都同意(在团队中)只需一次返回代码就更具可读性,但有些人担心优化
我知道过早优化是不好的。这是另一天的话题
我相信JIT编译器可以处理这个问题并跳过不必要的迭代,但是找不到任何信息来支持它JIT能够做到这一点吗强>
手头问题的代码示例:
public void boolean contains(MyThings things, String valueToFind) {
Iterator<Thing> thingIterator = things.iterator();
boolean valueFound = false;
while(thingIterator.hasNext()) {
Thing thing = thingIterator.next();
if (valueToFind.equals(thing.getValue())) {
valueFound = true;
}
}
return valueFound;
}
VS
public void boolean contains(MyThings things, String valueToFind) {
Iterator<Thing> thingIterator = things.iterator();
while(thingIterator.hasNext()) {
Thing thing = thingIterator.next();
if (valueToFind.equals(thing.getValue())) {
return true;
}
}
return false;
}
# 1 楼答案
不是真的。这只是老式的结构化编程,当时函数通常不保持小,保持值不变的范例还不流行
尽管存在争议,但使用非常小的方法(几行代码)并没有错,这些方法在不同的点返回。例如,在递归方法中,通常至少有一个基本情况立即返回,另一个基本情况返回递归调用返回的值
通常你会发现,创建一个额外的结果变量,只是为了保存返回值,然后确保函数的其他部分不会覆盖结果,当你已经知道你可以直接返回时,只会产生噪音,这会降低可读性,而不是增加可读性。读者必须处理认知负荷,才能看到结果不会被进一步修改。在调试过程中,这会更加增加痛苦
我不认为你的例子是过早的优化。它是搜索算法的逻辑和关键部分。这就是为什么可以从循环中
break
,或者在您的情况下,只返回值。我认为JIT不能轻易地意识到它应该打破循环。如果在集合中找到其他内容,它不知道是否要将变量更改回false
。(我认为意识到valueFound
不会变回false
并不明智)在我看来,您的第二个示例不仅可读性更强(变量
valueFound
只是额外的噪声),而且速度更快,因为它在执行任务时只返回。如果在设置valueFound = true
之后加上break
,第一个例子的速度会一样快。如果你不这样做,你有一百万个项目要检查,而你需要的项目是第一个,你将毫无意义地比较所有其他项目# 2 楼答案
Java编译器不能进行这样的优化,因为在一般情况下这样做会改变程序的逻辑
具体来说,添加一个提前返回将改变
thingIterator.hasNext()
的调用次数,因为第一个代码块将继续迭代集合到最后Java可能会用提前返回来取代
break
,但这会对程序的时间安排产生任何影响