Java性能与代码风格:从同一行代码进行多个方法调用

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

例如

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

也可以写成

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

就个人而言,我讨厌后者,因为它在同一行中进行了多次评估,并且我很难阅读代码。 这就是为什么我试图通过各种方式避免每行代码进行多次评估。 我也不知道jobParams.keySet()返回一个Set ,这让我感到jobParams.keySet()
另一个例子是:

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

VS

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

前者让我感到有毒和晕眩,因为我喜欢在每行代码中使用简单而干净的评估,当我看到其他人编写的代码时,我就讨厌它。

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

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

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

方法执行完成后,方法范围变量将符合GC的条件,因此即使您声明另一个变量,也可以,因为范围有限,并且您获得的优势将是可读的和主表代码。

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

在你的例子中:

 //like Set jobParamKeySet = jobParams.keySet(); Iterator jobParamItrtr = jobParamKeySet.iterator(); Could be also written as //dislike Iterator 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()

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

就我而言,我发现:

 Iterator jobParamItrtr = jobParams.keySet().iterator(); 

比以下更容易阅读:

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

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

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

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

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

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

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

我很难阅读代码。

更重要的是它不能过分陈述。

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

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

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

就个人而言,我不介意调用链接,因为它非常清楚,并且中间对象不太可能是空的(就像你的第一个“不喜欢”的例子)。 当它变得复杂时(表达式中的多个。),我更喜欢显式的局部变量,因为它更容易调试。

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

我没有看到a().b().c().dabcd更难读,人们似乎并不太在意。 (虽然我会打破它。)如果你不喜欢它,那就是一条线,你可以说

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

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

如果表现是您的关注(应该如此),首先要了解的不是让小东西出汗。 如果添加额外的局部变量需要付出任何代价,那么代码的其余部分在开始变得重要之前必须是无脂肪的。