Java方法调用与使用变量

时间:2009-12-17 18:51:29

标签: java performance

最近我和我的团队负责人讨论了使用临时变量和调用getter方法的问题。很长一段时间我认为,如果我知道我将不得不多次调用一个简单的getter方法,我会将它放入一个临时变量然后使用该变量。我认为这在风格和性能方面都会更好。但是,我的主管指出,在Java 4和更新版本中,这有点不正确。他相信使用一个较小的变量空间,所以他告诉我,调用getter方法的性能影响非常小,而不是使用temp变量,因此使用getter更好。但是,我并不完全相信他的论点。你们觉得怎么样?

14 个答案:

答案 0 :(得分:68)

永远不要为性能编码,始终为可读性编写代码。让编译器完成工作。

他们可以改进编译器/运行时以更快地运行良好的代码,突然间你的“快速”代码实际上会降低系统速度。

Java编译器&运行时优化似乎首先解决了更常见/可读的代码,因此您的“优化”代码更有可能在以后完全取消优化,而不是刚刚编写的代码。

注意:

这个答案指的是Java代码“Tricks”,就像引用的问题一样,可能会将循环级别从O(N)提高到O(N ^ 2)。通常写清洁,干燥代码并等待操作在修复之前花费太长时间。除非你是游戏设计师,否则你几乎永远不会达到这一点。

答案 1 :(得分:24)

你的领导是正确的。在VM的现代版本中,返回私有字段的简单getter被内联,这意味着不存在方法调用的性能开销。

答案 2 :(得分:14)

不要忘记通过将getSomething()的值赋给变量而不是将其调用两次,您假设getSomething()在第二次调用它时会返回相同的内容。也许这是你所谈论的场景中的一个有效假设,但有时却不是。

答案 3 :(得分:11)

这取决于。如果您想明确表示一次又一次使用相同的值,我会将其分配给临时变量。如果getter的调用有点冗长,我会这样做,比如myCustomObject.getASpecificValue()

如果代码可读,您将获得更少的错误。所以这是重点。

性能差异非常小或不存在。

答案 4 :(得分:8)

如果你记住代码的演变,v1.0中的简单getter往往会成为v2.0中不那么简单的getter。

将一个简单的getter更改为不那么简单的getter的编码器通常不知道有一个函数可以调用此getter 10次而不是1并且从不在那里修改它等等。

这就是为什么从DRY principal的角度来看,为重复使用缓存价值是有意义的。

答案 5 :(得分:6)

我不会牺牲“代码可读性”到几微秒 也许确实,getter表现更好,并且可以在运行时节省几微秒。但我相信,变量可以为你节省几个小时或者几天的时间来修复错误。

很抱歉非技术性的答案。

答案 6 :(得分:2)

我认为,如果满足某些条件,最近版本的JVM通常足够聪明地自动缓存函数调用的结果。我认为该函数必须没有副作用,并且每次调用时都可靠地返回相同的结果。请注意,对于简单的getter,这可能是也可能不是这种情况,具体取决于您的类中的其他代码对字段值执行的操作。

如果不是这种情况并且被调用的函数进行了重要的处理,那么你最好将其结果缓存在临时变量中。虽然电话的开销可能微不足道,但如果你打电话的频率超过必要的话,忙碌的方法会吃午餐。

我也练习你的风格;即使不是出于性能原因,我发现我的代码在没有完整的函数调用时更加清晰。

答案 7 :(得分:1)

如果它只是getFoo()则不值得。通过将其缓存到临时变量中,您可能不会更快,也可能会遇到麻烦,因为getFoo()可能会在以后返回不同的值。但是,如果它类似于getFoo().getBar().getBaz().getSomething(),并且您知道代码块中的值将不会更改,那么可能有理由使用临时变量来提高可读性。

答案 8 :(得分:0)

一般性评论:在任何现代系统中,除I / O外,不要担心性能问题。超快的CPU和大量内存意味着,所有其他问题在大多数情况下对系统的实际性能完全无关紧要。 [当然,有一些例外,如缓存解决方案,但它们很少见。]

现在遇到这个具体问题,是的,编译器将内联所有的获取。然而,即使这不是实际的考虑,真正重要的是所有可读性和代码流。如果调用多次使用,则更换局部变量的间接更好,例如customer.gerOrder()。getAddress()最好在局部变量中捕获。

答案 9 :(得分:0)

虚拟机可以比之后声明的任何局部变量更有效地处理前四个局部变量(参见lload and lload_<n> instructions)。因此缓存(内联)getter的结果实际上可能会损害您的性能。

当然,对他们自己要么性能影响几乎可以忽略不计,所以如果你想优化你的代码,请确保你真正解决了实际的瓶颈!

答案 10 :(得分:0)

不使用临时变量来包含方法调用结果的另一个原因是使用该方法可以获得最新的值。这可能不是实际代码的问题,但是当代码更改时它可能会成为一个问题。

答案 11 :(得分:0)

如果您确定getter将在整个范围内返回相同的值,我赞成使用temp变量。因为如果你有一个长度为10或者更长的变量,那么可读性方面看起来很糟糕。

答案 12 :(得分:0)

我用非常简单的代码测试了它:

  • 用一个简单的int getter创建了一个类(我尝试了Num的final和non-final值,没有看到任何区别,请注意它在案例中的数量为num永远不会改变......!):

    Num num = new Num(100_000_000);
    
  • 比较了2个不同的循环:

    1: for(int i = 0; i < num.getNumber(); ++i){(...)}
    
    2: number = num.getNumber();
    for(int i = 0; i < number; ++i){(...)}
    

结果在第一个中约为3毫米,在第二个中约为2毫米。因此,对于小循环而言,没有什么可担心的,在大型迭代中可能会出现更多问题,或者如果您总是调用getter并且需要它们很多。例如,在图像处理中,如果你想要快速,不要使用重复的吸气剂我会建议......

答案 13 :(得分:0)

我+1以保存变量。 1)可读性胜于性能-您的代码不仅适合您。 2)性能可能微不足道,但并非始终如此。我认为保持一致并树立先例很重要。因此,尽管对于一个局部变量而言可能无关紧要,但对于多次使用相同值多次或循环的较大类而言,则可能很重要。 3)易于更改实现/避免使用DRY代码。现在,您可以使用一种吸气剂从这一地方获得价值,理论上您在一堂课中使用吸气剂100次。但是在将来-如果您想更改获取值的方式/方式-现在必须将其更改100次,而不是将其保存为实例变量时更改一次。