性能-Java方法调用与使用变量
最近,我与团队负责人就使用临时变量与调用getter方法进行了讨论。 很长时间以来,我一直认为,如果我必须多次调用一个简单的getter方法,我会将其放入一个temp变量中,然后使用该变量。 我认为这在样式和性能上都会更好。 但是,我的负责人指出,在Java 4和更高版本中,这有些不正确。 他坚信使用较小的变量空间,因此他告诉我,与使用temp变量相比,调用getter方法对性能的影响很小,因此使用getters更好。 但是,我并不完全相信他的说法。 你们有什么感想?
Seagull asked 2020-06-20T05:40:11Z
14个解决方案
70 votes
永远不要为提高性能而编写代码,而总是为了提高可读性而编写代码。 让编译器完成工作。
他们可以改善编译器/运行时,以便更快地运行良好的代码,突然之间,“快速”代码实际上在减慢系统速度。
Java编译器和运行时优化似乎首先解决了更常见/可读的代码,因此,与刚刚编写的代码相比,您的“ Optimized”代码在以后的时间更有可能被取消优化。
注意:
这个答案是指Java代码“技巧”,就像所提到的问题一样,不是很糟糕的编程,它可能会提高从O(N)到O(N ^ 2)的循环级别。 通常,编写干净的DRY代码,然后等待操作花费很长时间才能修复它。 除非您是游戏设计师,否则您几乎永远不会达到这一点。
Bill K answered 2020-06-20T05:40:39Z
24 votes
您的线索是正确的。 在现代版本的VM中,内联了返回私有字段的简单getter,这意味着不存在方法调用的性能开销。
Randolpho answered 2020-06-20T05:40:59Z
14 votes
不要忘记通过将getSomething()的值分配给变量而不是两次调用它,您假设getSomething()在第二次调用它时将返回相同的东西。 在您所讨论的场景中,也许这是一个正确的假设,但有时并非如此。
Paul Clapham answered 2020-06-20T05:41:20Z
11 votes
这取决于。 如果您想清楚地说明您一次又一次使用相同的值,则可以将其分配给temp变量。 如果getter的调用有点长,例如myCustomObject.getASpecificValue(),我会这样做。
如果可读性强,您将在代码中得到更少的错误。 所以这是重点。
性能差异很小或根本不存在。
tangens answered 2020-06-20T05:41:49Z
8 votes
如果您牢记代码的演变,则v1.0中的简单getter往往在v2.0中变得不那么简单。
将简单的getter更改为不太简单的getter的编码人员通常不知道有一个函数会调用此getter 10次而不是1次,并且永远不会在那里进行更正,依此类推。
这就是为什么从DRY主体的角度来看,缓存值以供重复使用是有意义的。
Alexander Pogrebnyak answered 2020-06-20T05:42:18Z
6 votes
我不会将“代码可读性”牺牲到几微秒。
吸气器性能更好,可以在运行时中节省几微秒的时间,这也许是事实。 但是我相信,当错误修复时间到来时,变量可以为您节省几个小时甚至几天。
很抱歉提供非技术性答案。
Hendra Jaya answered 2020-06-20T05:42:47Z
2 votes
我认为,如果满足某些条件,JVM的最新版本通常足够聪明,可以自动缓存函数调用的结果。 我认为该函数必须没有副作用,并且每次调用都可靠地返回相同的结果。 请注意,对于简单的getter来说,可能会或可能不会,取决于类中其他代码对字段值所做的操作。
如果不是这种情况,并且被调用的函数进行了大量处理,那么将其结果缓存在临时变量中确实会更好。 尽管呼叫的开销微不足道,但是如果您呼叫午餐的次数过多,那么繁忙的方法就会吃掉您的午餐。
我也会练习你的风格; 即使不是出于性能原因,当我的代码中没有很多函数调用时,我也会觉得代码更清晰。
Carl Smotricz answered 2020-06-20T05:43:16Z
1 votes
如果仅仅是getFoo(),这是不值得的。通过将其缓存到temp变量中,您并没有使其变得更快,并且可能自找麻烦,因为getFoo()以后可能会返回不同的值。 但是,如果它类似于getFoo().getBar().getBaz().getSomething(),并且您知道该值不会在代码块内更改,则可能有理由使用temp变量以提高可读性。
fastcodejava answered 2020-06-20T05:43:37Z
0 votes
一般评论:在任何现代系统中,除I / O之外,都不必担心性能问题。 快速的CPU和大量的内存意味着所有其他问题在大多数时候对系统的实际性能完全不重要。 [当然,也有诸如缓存解决方案之类的例外,但是它们很少而且很少见。]
现在要解决这个特定问题,是的,编译器将内联所有获取。 但是,即使这不是实际的考虑因素,真正重要的还是整个代码的可读性和流程。 如果使用多次调用(例如customer.gerOrder()。getAddress())更好地捕获在局部变量中,则用局部变量代替间接调用会更好。
user234054 answered 2020-06-20T05:44:03Z
0 votes
与之后声明的任何局部变量相比,虚拟机可以更有效地处理前四个局部变量(请参见lload和lload_ 指令)。 因此,缓存(内联)getter的结果实际上可能会损害您的性能。
当然,它们对性能的影响几乎可以忽略不计,因此,如果要优化代码,请确保确实解决了实际的瓶颈!
Bombe answered 2020-06-20T05:44:28Z
0 votes
不使用临时变量来包含方法调用结果的另一个原因是,使用该方法可以获得最新的值。 实际的代码可能不会有问题,但是更改代码后可能会成为问题。
kiamlaluno answered 2020-06-20T05:44:49Z
0 votes
如果您确定getter将在整个范围内返回相同的值,则我建议使用temp变量。 因为如果您的变量名称的长度为10或更大,则getter在可读性方面看起来很糟糕。
Rishikesh Chaudhari answered 2020-06-20T05:45:09Z
0 votes
我已经用非常简单的代码对其进行了测试:
用int的简单getter创建了一个类(我用Num的final和non-final值进行了尝试,没有发现任何区别,请注意,在这种情况下,num永远也不会改变...!):
1: for(int i = 0; i < num.getNumber(); ++i){(...)}
2: number = num.getNumber();
for(int i = 0; i < number; ++i){(...)}
比较2个不同的for循环:
1: for(int i = 0; i < num.getNumber(); ++i){(...)}
2: number = num.getNumber();
for(int i = 0; i < number; ++i){(...)}
结果大约是第一个3毫秒,第二个大约2毫秒。 因此,两者之间存在微小差异,对于小循环,无需担心,在大迭代中或者如果您始终调用getter并非常需要它们,可能会遇到更多问题。 例如,在图像处理中,如果您想变得更快,请不要重复使用吸气剂,我建议...
Nicolas Zimmermann answered 2020-06-20T05:45:51Z
0 votes
我为保存变量+1。1)可读性胜于性能-您的代码不仅适合您。2)性能可能微不足道,但并非始终如此。 我认为保持一致并树立先例很重要。 因此,尽管对于一个局部变量而言可能无关紧要,但是对于较大的类而言,多次使用相同的值或者在循环的情况下,它可能至关重要。3)易于更改实现/避免使用DRY代码。 现在,您可以使用吸气剂从这一地方获得价值,并且理论上讲,您在一堂课中使用吸气剂100次。 但是在将来-如果您想更改获取值的方式/方式-现在必须将其更改100次,而不是将其另存为实例变量时更改一次。
DLindz answered 2020-06-20T05:46:12Z