避免间接和冗余方法调用

时间:2015-10-05 10:10:29

标签: java android

我目前正在审核包含此内容的PullRequest:

-        for (int i = 0; i < outgoingMassages.size(); i++) {
+        for (int i = 0, size = outgoingMassages.size(); i < size; i++) 

https://github.com/criticalmaps/criticalmaps-android/pull/52

不知怎的,我感觉不对 - 会认为虚拟机正在进行这些优化 - 但不能确切地说。如果这个改变有意义,或者确认这是在VM端完成的,那么我们会喜欢获得一些输入。

5 个答案:

答案 0 :(得分:5)

不,不确定VM是否会改变您的代码

 -        for (int i = 0; i < outgoingMassages.size(); i++) {

 +        for (int i = 0, size = outgoingMassages.size(); i < size; i++) 

在for循环中,outgoingMassages可能会改变其大小。因此,这种优化不能由JVM应用。如果这是共享资源,另一个线程也可以更改outgoingMassages大小。

只有在行为没有改变的情况下,JVM才能更改代码。例如,它可以将一个字符串连接列表替换为StringBuilder的附加序列,或者它可以内联一个简单的方法调用,或者如果它是一个常量值,则可以计算一个循环外的值。

答案 1 :(得分:1)

VM不会执行此优化。由于size() - Method可能不会在每次调用时返回相同的结果。因此必须在每次迭代时调用该方法。

但是,如果尺寸是一种简单的吸气方法,则性能影响非常小。可能无法衡量。 (在少数情况下,它可能使Java能够使用并行化,这可能会产生影响,但这取决于循环的内容)。

更大的差异可能是确保for循环具有预先已知的迭代量。在这个例子中,我似乎没有意义。但也许被调用的方法可能会返回不需要的变化结果?

答案 2 :(得分:0)

如果集合中的size()方法只是提供私有字段的值,那么VM将优化其中的大部分(但不是全部)。它通过内联size()方法来实现,这样它就可以访问该字段。

未获得优化的剩余位是新代码中的size将被视为final,因此会保持不变,而从该集合中获取的字段将赢得&#39 ;被视为final(也许它是从另一个线程修改过来的)。因此,在原始情况下,每次迭代都会读取字段,但在新的情况下,它会赢得。

答案 3 :(得分:0)

任何体面的优化器 - 无论是在VM还是在编译器中 - 都可能会识别出来:

class Messages {

    int size;

    public int size() {
        return size;
    }
}

public void test() {
    Messages outgoingMassages = new Messages();
    for (int i = 0; i < outgoingMassages.size(); i++) {

    }
}

并将其优化为

    for (int i = 0; i < outgoingMassages.size; i++) {

执行额外的 - 未经测试 - 因此应优先考虑evil

答案 4 :(得分:0)

方法调用将在循环的每次迭代时发生,并且不是免费的成本。由于您无法预测这种情况发生的频率,因此将其称为一次将始终 。这是一个次要的优化,但您不应该依赖编译器为您进行优化。

此外,会员outgoingMassages ..

private ArrayList<OutgoingChatMessage> outgoingMassages ..

...应该是一个界面:

private List<OutgoingChatMessage> outgoingMassages ..

然后,调用.size()将成为虚拟方法。要找出特定的对象类,将为层次结构的所有类调用方法表。这不是免费的。

相关问题