41

在下面的代码中,我们调用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对象?

4

6 回答 6

49

我几乎总是更喜欢局部变量解决方案。

内存占用

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

表现

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

可读性

遵循DRY原则。在您的情况下,这几乎不重要,因为局部变量名称与方法调用一样长,但对于更复杂的情况,它具有可读性,因为您不必找到两个表达式之间的10 个差异。如果您知道它们是相同的,那么请使用局部变量进行说明。

正确性

想象一下你SelectItem不接受nulls 并且你的程序是多线程的。的值listType.getDescription()可能会在此期间发生变化,而您已经敬酒了。

调试

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


省略局部变量唯一能取胜的就是节省一行。所以我只会在它真的无关紧要的情况下这样做:

  • 很短的表达
  • 不可能同时进行修改
  • 简单的私有最终获取器
于 2013-10-18T09:57:40.407 回答
8

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

于 2013-10-18T09:10:47.950 回答
2

我不确定是否是首选。我喜欢清晰可读的代码而不是性能代码,尤其是在性能提升可以忽略不计的情况下。在这种情况下,我怀疑几乎没有明显的区别(尤其是考虑到 JVM 的优化和代码重写能力)

于 2013-10-18T09:10:54.497 回答
2

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

于 2013-10-18T09:15:39.663 回答
2

我同意一切。关于可读性我想补充一点:我看到很多程序员在做这样的事情:

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 个 getter 链,请使用中间变量。它更容易阅读和调试

于 2020-06-01T18:01:21.783 回答
0

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

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

于 2016-03-21T15:39:37.683 回答