Java编译器能否优化循环以尽早返回?

时间:2018-12-14 13:49:50

标签: java performance jit

我正在使用一个外部库,该库决定自行处理集合。不使用它或进行更新是我无法控制的。要使用此第三方“集合”的元素,它仅返回迭代器。

在代码审查过程中出现了一个问题,关于在代码中获得多次回报以提高性能。我们都同意(在团队内部)该代码可读性更高,只需返回一次,但是有些人担心优化。

我知道过早的优化是不好的。这是另一天的话题。

我相信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;
}

2 个答案:

答案 0 :(得分:3)

  

我们都同意该代码可读性更高,只需返回一次即可。

不是。这只是老式的结构化编程,当时函数通常不会变小,并且保持值不变的范式还不流行。

尽管存在争议,但使用非常小的方法(少数几行代码)并在不同的点返回是没有错的。例如,在递归方法中,通常至少有一个立即返回的基本案例,以及另一个返回由递归调用返回的值的案例。

通常,您会发现创建一个额外的结果变量,只是为了保存返回值,然后确保该函数的其他部分都不会覆盖结果;当您已经知道可以返回结果时,就会产生噪声,从而使其可读性不高。读者必须应对认知超负荷,才能看到结果没有进一步修改。在调试过程中,这会更加增加痛苦。

我不认为您的榜样是过早的优化。这是搜索算法的逻辑和关键部分。这就是为什么您可以从循环中break,或者就您而言,只返回值的原因。我认为JIT无法轻易意识到应该打破循环。如果您在集合中找到其他内容,则不知道是否要将变量改回false。 (我认为意识到valueFound不会变回false并不明智)。

在我看来,您的第二个示例不仅更具可读性(valueFound变量只是额外的噪音),而且速度更快,因为它只是在工作时返回。如果在设置break之后放置valueFound = true,第一个示例将很快。如果您不这样做,则需要检查一百万个项目,而您需要的是第一个项目,那么您将毫无疑问地比较所有其他项目。

答案 1 :(得分:1)

Java编译器无法进行这样的优化,因为通常情况下这样做会改变程序的逻辑。

具体来说,添加早返回将改变thingIterator.hasNext()的调用次数,因为您的第一个代码块将继续对集合进行迭代直至结束。

Java可能会以提早返回的方式替换break,但这将对程序的时间产生任何影响。