5

场景是我需要至少访问一个值两次。即我正在使用记录器来跟踪应用程序中发生的事情。我想记录对象的名称,该函数正在运行,然后用相同的名称做一些事情(即检查它是否包含一些字符串或将其放入数组中)。

将名称存储在变量中:

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());
}

我了解,在第一种情况下,我将创建一个新字符串,为其分配一个值,然后检索该值两次。这样我使用了更多的内存资源,对吗?

在第二种情况下,我是否两次访问对象栏,然后两次访问它的名称。我想这不是 DRY 方法。但另一方面,我并没有在记忆中重复自己,对吗?

哪种方法更好?

4

3 回答 3

3

在第一个示例中,您没有使用更多内存,因为String它是一个不可变对象。因此,对 String 的任何引用都只是指向内存中同一对象的指针。

后一个选项还存在一些线程安全问题,其中getName()调用之间的结果可能会发生变化。尽管可能不太可能,但您可能需要考虑这一点。

考虑到这一点,我会推荐第一个选项,即使它更“健谈”。

注意:也有可能getName()是由计算生成的,在这种情况下,您实际上最终会使用第二种方法比第一种方法使用更多的内存。

于 2012-10-05T13:33:02.383 回答
1

Bar应该不可变的类(对于大多数情况)。对于不可变类,这些方法是相同的,因此您可以选择任何您喜欢的方法。

只有在Bar可变的情况下才会出现任何真正的问题,因此 的值bar.name可以在 2 次读取之间变化。但是这种情况下将使用Bar作为域对象(它似乎是)毫无意义。您可以通过barfoo(). 然后,再次,一旦您拥有 original 的本地副本bar,您可以选择您更喜欢的任何方式。

所以,这是品味问题。是的,在第一种情况下,您可能会浪费一点点内存用于本地引用,但最有可能的是,JVM 会对其进行优化,使其看起来像字节码级别的第二种方式。

于 2012-10-05T13:31:24.310 回答
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

有些人会争辩说删除临时变量可能会导致性能问题。

正如马丁·福勒所说:

在这种情况下,您可能会担心性能。与其他性能问题一样,暂时让它滑动。十有八九,没关系。当它确实重要时,您将在优化期间解决问题。随着您的代码得到更好的分解,您通常会发现更强大的优化,而如果不进行重构,您可能会错过这些优化。如果情况变得更糟,很容易恢复温度。

但无论如何,这是一个品味问题。有些人发现第一种方法更具可读性,而另一些人则认为第二种方法更具可读性。我真的更喜欢第二个,因为我讨厌临时变量添加没有实际值的行:)

于 2012-10-05T13:32:48.850 回答