在对象上调用getter而不是将其存储为局部变量(内存占用,性能)

时间:2013-10-18 09:07:56

标签: java performance readability memory-consumption

在下面的代码中,我们拨打了listType.getDescription()两次电话:

for (ListType listType: this.listTypeManager.getSelectableListTypes())
{
    if (listType.getDescription() != null)
    {
        children.add(new SelectItem( listType.getId() , listType.getDescription()));
    }
}

我倾向于重构代码以使用单个变量:

for (ListType listType: this.listTypeManager.getSelectableListTypes())
{
    String description = listType.getDescription();

    if (description != null)
    {
        children.add(new SelectItem(listType.getId() ,description));
    }
}

我的理解是JVM以某种方式针对原始代码进行了优化,尤其是嵌套调用children.add(new SelectItem(listType.getId(), listType.getDescription()));

比较两个选项,哪一个是首选方法,为什么?这就是内存占用,性能,可读性/易用性以及其他我现在不想到的。

后一个代码片段何时变得比前者更有利,也就是说,当使用临时局部变量变得更加可取时,listType.getDescription()调用是否有任何(近似)数量,因为listType.getDescription()始终如此需要一些堆栈操作来存储this对象?

6 个答案:

答案 0 :(得分:33)

我几乎总是喜欢本地变量解决方案。

内存占用

单个局部变量需要4或8个字节。它是一个参考,没有递归,所以让我们忽略它。

性能

如果这是一个简单的getter,JVM可以自己记忆,所以没有区别。如果这是一个无法优化的昂贵电话,手动记忆会使其更快。

可读性

遵循DRY原则。在你的情况下,它几乎不重要,因为局部变量名称在字符方面与方法调用一样长,但对于更复杂的东西,它是可读性的,因为你不必在两个表达式之间find the 10 differences。如果您知道它们是相同的,那么使用局部变量清楚地说明。

正确性

想象一下,您的SelectItem不接受null,您的程序是多线程的。 listType.getDescription()的价值可能会在此期间发生变化而且你会被烘烤。

调试

拥有包含有趣值的局部变量是一个优势。


通过省略局部变量获得的唯一胜利就是保存一行。所以我只会在无关紧要的情况下这样做:

  • 非常短的表达
  • 无法进行并发修改
  • 简单的私人最后的getter

答案 1 :(得分:7)

我认为第二种方式肯定更好,因为它提高了代码的可读性可维护性,这是最重要的事情。除非你编写一个每毫秒都很重要的应用程序,否则这种微优化不会对你有任何帮助。

答案 2 :(得分:2)

我不确定是否首选。我 喜欢的是清晰可读的代码,而不是高性能代码,特别是当性能增益可以忽略不计时。在这种情况下,我怀疑接下来没有明显的区别(特别是考虑到JVM的优化和代码重写功能)

答案 3 :(得分:1)

在命令式语言的上下文中,函数调用返回的值无法被记忆(参见http://en.m.wikipedia.org/wiki/Memoization),因为无法保证函数没有副作用。因此,您的策略确实避免了函数调用,代价是分配临时变量来存储对函数调用返回的值的引用。 除了稍微高效一点(除非在循环中多次调用该函数,这并不重要),我会选择你的风格,因为更好的代码可读性。

答案 4 :(得分:0)

只有当局部变量的名称是自我记录时,我才同意局部变量方法的可读性。称它为“描述”是不够的(哪种描述?)。将其称为“selectableListTypeDescription”将使其清楚。我想抛出for循环中的递增变量应命名为“selectableListType”(特别是如果“listTypeManager”具有其他ListTypes的访问器)。

另一个原因是,如果无法保证这是单线程的,或者您的列表是不可变的。

答案 5 :(得分:0)

我同意所有事情。关于可读性,我想添加一些内容: 我看到很多程序员在做类似的事情:

if(item.getFirst()。getSecond()。getThird()。getForth()== 1 ||

item.getFirst()。getSecond()。getThird()。getForth()== 2 ||

item.getFirst()。getSecond()。getThird()。getForth()== 3)

或更糟的是:

item.getFirst()。getSecond()。getThird()。setForth(item2.getFirst()。getSecond()。getThird()。getForth())

如果要多次调用10个吸气剂的同一链,请使用中间变量。读取和调试起来要容易得多