java嵌套函数定义_函数嵌套调用性能好还是函数分开写性能好?

函数嵌套调用性能好还是分开写性能好?

下午突然想到一个问题:

* 形式如下的两种方法,哪一种的效率更高一点?

第一种:

A=fun1(args1[]);

B=fun2(A,args2[]);

C.fun3(B);

1

2

3

第二种:

C.fun3(fun2(fun1(args1[]),args2[]));

1

也就是说,一段结果相同的代码,是将中间使用的函数嵌套起来写性能更好还是分开写性能更高呢?

这里假定变量不会再被后面的代码使用,不存在复用的问题,同时,也将可读性问题暂放一边,仅仅从性能角度考虑。

直觉上,应当是第二种形式的性能更高一些,减少了中间变量存储,但是我还是有一点迷惑:函数调用时系统要保存现场,对各种变量在栈中进行保存,调用完了还要恢复现场,恢复各种上一个方法中的值,第二种形式是不是在这方面消耗了更多性能呢?毕竟在第二种形式中,刚想调用fun3,发现还要调用fun2,刚想调用fun2,发现还必须先调用fun1。

本着先敲一敲看看的想法,我用java写了一个测试代码(放到文章最后面),从javap反编译的中间代码上能看出上面两个问题的答案:

第一种形式:

第二种形式:

从代码上,可以看出,第一种形式的确会多保存两个临时变量,多了成对的两个命令’astore’、’aload’从寄存器中存读变量。

而第二种形式在编译成中间代码之后,函数的调用顺序也变成了fun1->fun2->fun3,而且没有中间变量。

后来我又想了想,其实第一种形式和第二种形式函数调用对栈的影响次数是一样的,即便第二种函数切换频繁,在机器层面也是按部就班地做,性能上应当相同。

结论:

第二种形式在性能上更优

题外话:

在看反编译的中间代码时我发现,即便普通的字符串拼接,到了java字节码的层次,也是通过StringBuilder完成的,也就是说简单的字符串拼接,性能上应当和使用StringBuilder一样,字符串拼接在这里不会形成性能瓶颈,但是也有例外。

比如,我在下面的测试代码里用的那样,在for循环中循环字符串拼接,这个时候会反复调用StringBuilder的toString方法,导致产生大量的String挤占堆空间,结果我的测试代码就显示OOM了,所以如果要使用以下代码请调节循环次数。

从1中可以看出,其实我测试代码有问题,本来想找个耗时的操作区分两种形式代码的性能,所以使用了String的拼接,结果循环次数一多就OOM,也就是说我没从实践中真实测得两种形式代码的差别(即便循环次数少的情况下,多次测量结果也是千奇百怪,我怀疑系统对程序的调度影响了耗时)

以下我写的测试代码:

public class AnyIdeaTestFirst{

/**

* 静态内部类,用于返回一个记录方法耗时和字符串的集合

*/

static class Iner{

String s;

long time;

public String getS() {

return s;

}

public void setS(String s) {

this.s = s;

}

public long getTime() {

return time;

}

public void setTime(long time) {

this.time = time;

}

}

public static Iner fun1(String a){

long timeBefore=System.currentTimeMillis();

for(int i=0;i<50;i++){

a+=a;

}

Iner iner=new Iner();

iner.setS(a);

long timeAfter=System.currentTimeMillis();

iner.setTime(timeAfter);

System.out.println("fun1 after:"+(timeAfter-timeBefore));

return iner;

}

public static Iner fun2(Iner iner,String a){

long timeBefore=System.currentTimeMillis();

System.out.println("进入fun2,与退出fun1之间的时间差:"+(timeBefore-iner.getTime()));

for(int i=0;i<30;i++){

iner.setS(a);;

}

long timeAfter=System.currentTimeMillis();

iner.setTime(timeAfter);

System.out.println("fun1 after:"+(timeAfter-timeBefore));

return iner;

}

public static void fun3(Iner iner){

long timeBefore=System.currentTimeMillis();

System.out.println("进入fun3,与退出fun2之间的时间差:"+(timeBefore-iner.getTime()));

}

public static void main(String []args){

System.gc();

System.out.println("方法一开始-------------------------------"+System.currentTimeMillis());

Iner iner1=fun1("a");

Iner iner2=fun2(iner1,"b");

fun3(iner2);

System.out.println("方法一结束--------------------------------"+System.currentTimeMillis());

System.out.println("方法二开始--------------------------------"+System.currentTimeMillis());

fun3(fun2(fun1("c"),"d"));

System.out.println("方法二结束--------------------------------"+System.currentTimeMillis());

}

}

---------------------

作者:lqadam

来源:CSDN

原文:https://blog.csdn.net/lqadam/article/details/53395019

版权声明:本文为博主原创文章,转载请附上博文链接!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值