场景是我需要至少访问两次值。即我正在使用记录器来跟踪应用程序中发生的情况。我想记录对象的名称,该函数正在处理,稍后使用相同的名称(即检查它是否包含某些字符串或将其放入数组中)。
将名称存储在变量中:
foo(Bar bar){
String name = bar.getName();
logger.info("I am working with "+name);
this.doSomethingWith(name);
}
或者两次调用getName():
foo(Bar bar){
logger.info("I am working with "+bar.getName());
this.doSomethingWith(bar.getName());
}
据我所知,在第一个场景中,我将创建一个新的String,为其赋值,然后检索此值两次。这样我使用更多的内存资源,对吗?
在第二种情况下,我是否访问了对象栏两次,然后两次访问它的名称。我想这不是一种干燥方法。但另一方面,我不是在记忆中重复自己,对吗?
哪种方法更好?
答案 0 :(得分:3)
在第一个示例中,您没有使用更多内存,因为String
是一个不可变对象。因此,对String的任何引用都只是指向内存中同一对象的指针。
后一个选项还存在一些线程安全问题,其中getName()
的结果可能会在调用之间发生变化。尽管可能不太可能,但您可能需要考虑这一点。
考虑到这一点,我会推荐第一个选项,即使它更“说话”。
注意:getName()
也可能是通过计算生成的,在这种情况下,您实际上最终会使用比第一种方法更多的内存。
答案 1 :(得分:1)
您的Bar
应该是不可变类(对于大多数情况而言)。对于不可变类,这些方法是相同的,因此您可以选择任何您喜欢的方法。
只有Bar
可变时才会出现任何实际问题,因此bar.name
的值可以在2次读取之间发生变化。但是这种情况会使用Bar
作为域对象(它似乎是)毫无意义。您可以通过在bar
顶部创建foo()
的本地副本来解决此类问题。然后,再次,一旦你有原始bar
的本地副本,你可以选择你喜欢的任何方式。
所以,这是品味问题。是的,在第一种情况下,可以浪费一点内存用于本地引用,但最有可能的是,JVM会优化它以使其在字节码级别上看起来像第二种方式。
答案 2 :(得分:1)
就个人而言,我更喜欢第二种方法。 实际上,我通常只在必要时创建临时变量。
Martin Fowler(http://en.wikipedia.org/wiki/Martin_Fowler)也遵循本指南。他在我读过的书中谈到了这一点:
http://www.amazon.fr/Refactoring-Improving-Design-Existing-Code/dp/0201485672
关于这个主题的书的免费摘录在这里:
http://sourcemaking.com/refactoring/replace-temp-with-query
有些人会认为删除临时变量可能会导致性能问题。
正如Martin Fowler所说:
在这种情况下,您可能会担心表现。和其他一样 性能问题,让它暂时滑动。九次出局 十,没关系。当它重要时,你将解决问题 在优化期间。有了更好的代码,你会经常 找到更强大的优化,没有你会错过 重构。如果情况变得更糟,那么放温度就很容易了 回来。
但无论如何,这是一个品味问题。有些人发现第一种方法更具可读性,第二种方式则更有可我真的更喜欢第二种,因为我讨厌临时变量添加没有实际值的行:)