Java中长方法链的优化

Java中长方法链的优化,java,optimization,methods,chaining,Java,Optimization,Methods,Chaining,通过分析应用程序中一些预先存在的第三方Java代码(无法重新编写),我发现它几乎完全是以这种形式构建在长方法链上的 public Object process() { // Do some class-specific stuff return this.getChild().process(); } return getChild().process(); 其中有一个基类定义了process() 作为条件块的结果,在运行时创建(分支)多个这样的链,其中一些可能会相对较早地返回(例如

通过分析应用程序中一些预先存在的第三方
Java
代码(无法重新编写),我发现它几乎完全是以这种形式构建在长方法链上的

public Object process() {
  // Do some class-specific stuff
  return this.getChild().process();
}
return getChild().process();
其中有一个基类定义了
process()

作为条件块的结果,在运行时创建(分支)多个这样的链,其中一些可能会相对较早地返回(例如,在链中10-20个“链接”之后),但最常见的是,链的“长度”要大得多,甚至可以在返回结果之前超过100个连续的方法调用

应用程序使用此代码处理大型文件,每次调用顶级方法的结果都会发生变化,通常每个文件的每一行都会发生变化

因此,有两个问题:

  • 与“常规”设计相比,这种设计对性能的影响是什么
  • 是否有任何技巧可以显著提高代码的性能(例如,通过更改一些JVM参数)

方法调用非常快(每秒10秒或100秒数百万次),因此首先通过分析系统来确保它实际上是有益的

否则,您可以使用缓存来提高效率,尤其是在结果一致(相同的输入,相同的输出)的情况下

例:


如果涉及到某种类型的输入或状态,则可以对缓存使用
Map
,该缓存使用输入值的键并存储输出值的值。

表单的语句

public Object process() {
  // Do some class-specific stuff
  return this.getChild().process();
}
return getChild().process();
这与

SomeType var = getChild();
return var.process();
在这两种情况下,将依次调用一个方法,并且
getChild()
的返回值将用作
process()
调用的接收器

如果您正在寻找不相关的次要技术细节,那么第一种形式不需要局部变量。但由于在HotSpot中,在创建线程时预先分配了一个固定大小的堆栈内存,所以无法察觉这两种形式之间的性能差异


这两种形式之间的选择纯粹是风格上的选择。

是的,这是一个明显的(也是聪明的)选择,但不适用于这种情况,因为代码用于处理大文件,并且结果在每一行都会发生变化。我在问题中澄清了这一点。谢谢,还有+1.:-)@PNS需要更多细节。一定有你可以缓存的东西。否则,方法调用的速度非常快(每秒上千万次),因此您可能不需要担心。IMO“非常快”和每秒上千万次是矛盾的。同时,像添加两个整数这样的正常操作每秒可以执行数十亿次,如果你有一个好的CPU,则可以执行超过100亿次。@harold是的,速度是相对的,但是当你可以在毫秒内完成50万次时,没有理由担心100次方法调用为什么你认为这是一个性能问题?您是否有分析数据来支持您的担忧?什么是“常规”架构?这里根本不清楚你在问什么。我所说的“常规”是指具有短方法链的体系结构。问题在于评估任何绩效影响。如果共识是“没有预期的性能影响”,那么就这样吧。没有“长方法链”和“短方法链”的区别,您可以通过任何一种方式获得深层调用堆栈。由于调用深度而担心性能可能是浪费时间,除非您已经分析了系统并确定了瓶颈。我认为他的担心与以下事实有关:这是一个递归调用,有时深入到100个级别,不仅仅是它一个接一个地调用两个方法。@Holger,除非某个JVM再次在链接方面做了一些有趣的事情:)@DaveCousineau:这就是答案的要点,没有递归。这两个链式调用与具有中间赋值的两个调用没有区别。一旦你理解了这一点,你就会明白这同样适用于一百个链式调用。它们与一系列未加约束的调用仍然没有区别。用一百次调用写下来只会把答案弄得乱七八糟。@Eugene:但这实际上与链接无关,而是与优化更常见的模式有关。