6

我很好奇在同一行代码中打包多个和/或嵌套的方法调用是否对性能更好,这就是为什么一些开发人员这样做的原因,其代价是降低了代码的可读性。

例如

//like
Set<String> jobParamKeySet = jobParams.keySet();
Iterator<String> jobParamItrtr = jobParamKeySet.iterator();

也可以写成

//dislike    
Iterator<String> jobParamItrtr = jobParams.keySet().iterator();

就个人而言,我讨厌后者,因为它在同一行中进行多次评估并且我很难阅读代码。这就是为什么我尽量避免每行代码有多个评估。我也不知道jobParams.keySet()返回 aSet并且这让我很烦恼。
另一个例子是:

//dislike
Bar.processParameter(Foo.getParameter());

对比

//like
Parameter param = Foo.getParameter();
Bar.processParameter(param);

前者让我讨厌和头晕,因为我喜欢在每一行代码中使用简单而干净的评估,当我看到其他人的代码这样写时我只是讨厌它。

但是在同一行中打包多个方法调用有什么(性能)好处吗?

编辑:由于@stemm 的提醒,单行也更难调试

4

7 回答 7

6

微优化是杀手锏。如果您显示的代码引用是实例范围(或)方法范围,我将采用第二种方法。

一旦方法执行完成,方法范围变量将有资格进行 GC,因此即使您声明另一个变量,也没关系,因为范围是有限的,您获得的优势将是可读的主表代码。

于 2012-10-09T14:45:09.873 回答
5

我倾向于不同意此列表中的大多数其他人。实际上,我发现第一种方式更清晰,更易于阅读。

在您的示例中:

//like
Set<String> jobParamKeySet = jobParams.keySet();
Iterator<String> jobParamItrtr = jobParamKeySet.iterator();
Could be also written as

//dislike    
Iterator<String> jobParamItrtr = jobParams.keySet().iterator();

第一种方法(您喜欢的方法)有很多不相关的信息。例如,迭代器接口的全部意义在于为您提供一个标准接口,您可以使用它来循环任何支持的实现。因此,它是一个键集这一事实与代码本身无关。您正在寻找的只是遍历已实现对象的迭代器。

其次,第二个实现实际上为您提供了更多信息。它告诉您代码将忽略 jobParams 的实现,并且只会循环遍历键。在第一个代码中,您必须首先追溯 jobParamKeySet 是什么(作为一个变量)以找出您正在迭代的内容。此外,您不知道在范围内的其他地方是否/在哪里使用了 jobParamKeySet。

最后,作为最后的评论,第二种方式更容易在必要时切换实现;在第一种情况下,您可能需要重新编码两行(第一个变量赋值,如果它从一个集合更改为其他内容),而第二种情况您只需要更改一行。

话虽这么说,但凡事都有限度。在一行中链接 10 个调用可能很难阅读和调试。然而,3 或 4 个级别通常是明确的。有时,特别是如果多次需要中间变量,显式声明它更有意义。

在您的第二个示例中:

//dislike
Bar.processParameter(Foo.getParameter());
vs

//like
Parameter param = Foo.getParameter();
Bar.processParameter(param);

我发现实际上更难以准确理解Bar.processParameter(param). 我需要更长param的时间来匹配变量实例化才能看到它是Foo.getParameter(). 而在第一种情况下,信息非常清晰并且呈现得非常好 - 您正在处理Foo.getParameter()参数。就个人而言,我发现第一种方法也不太容易出错 -Foo2.getParamter()当它在同一个调用中而不是单独的行中时,你不太可能意外使用它。

于 2012-10-09T15:22:16.260 回答
3

少了一个变量赋值,但即使是编译器也可以在某些情况下对其进行优化。我不会为了性能而这样做,这是一种早期的优化。编写更易于维护的代码。

就我而言,我发现:

Iterator<String> jobParamItrtr = jobParams.keySet().iterator();

比以下更容易阅读:

Set<String> jobParamKeySet = jobParams.keySet();
Iterator<String> jobParamItrtr = jobParamKeySet.iterator();

但我想这是个人品味的问题。

于 2012-10-09T14:44:58.627 回答
1

代码永远不会由同一用户开发。我会选择第二种方式。也更容易理解和维护。

当两个不同的团队在不同的位置处理代码时,这也是有益的。

很多时候,如果他使用第一个选项,我们需要一个小时或更长时间来了解其他开发人员做了什么。我个人多次遇到这种情况。

于 2012-10-09T14:48:18.627 回答
1

但是在同一行中打包多个方法调用有什么(性能)好处吗?

我严重怀疑差异是可衡量的,但即使有我也会考虑

我很难阅读代码。

更重要的是,它不能被夸大。

即使它的速度只有一半,我仍然会编写最简单、最干净和最容易理解的代码,只有当你分析了应用程序并确定你有问题时,我才会考虑优化它。

顺便说一句:我更喜欢更密集的链接代码,但我建议您使用您喜欢的代码。

于 2012-10-09T15:13:48.093 回答
1

省略额外的局部变量可能具有可忽略的性能优势(尽管 JIT 可能能够优化这一点)。

就我个人而言,我不介意调用链接,因为它非常清楚做了什么并且中间对象不太可能为空(比如你的第一个“不喜欢”示例)。当它变得复杂时(表达式中有多个 .),我更喜欢显式的局部变量,因为它调试起来非常简单。

所以我根据具体情况决定我喜欢什么:)

于 2012-10-09T15:14:23.080 回答
0

我看不出哪里比人们似乎不太介意的地方a().b().c().d更难阅读。a.b.c.d(虽然我会把它拆开。)如果你不喜欢这一切都在一条线上,你可以说

a()
 .b()
 .c()
 .d

(我也不喜欢那样。)我更喜欢使用几个额外的变量来分解它。它使调试更容易。

如果性能是您关心的问题(应该如此),首先要了解的是不要为小事出汗。如果添加额外的局部变量需要付出任何代价,那么在它开始变得重要之前,其余的代码就必须是无脂肪的。

于 2012-10-09T19:25:26.920 回答