java开发for循环优化原则

场景 : 最近,有客户反应某些功能执行得很慢,我们于是对代码日志进行了定位,我们的系统架构是nginx+tomcat; 我们可以直接定位到tomcat的catalina日志,但是后来吧,我们这边统一要整理响应时间超过5S以上的,对这些都要进行整改;所以我们先直接分析nginx的日志文件,查看请求跟响应超过5S以上的统计出来,然后在tomcat的日志当中定位这些请求,查找到具体的时间,以及上下文,最后我们定位到某个方法执行超过一些时间的。现在,我们抛开掉业务场景,从最近本的优化方案看。

目录

1)拆分操作原则 

2)普通变量 改为 寄存器变量

3)外小内大”原则

4)提取与循环无关的表达式

5)消除循环终止判断时的方法调用

6)异常捕获

7)尝试使用map结构查询的执行方式; 

8)减少循环变量的实例化,比如:


1)普通变量 改为 寄存器变量

转载来于:https://blog.csdn.net/u011236602/article/details/81092504

i++ 改为 ++i;

int i=0, j;
j=++i; //前置版本,运算对象先自增1,然后将改变后的对象作为求值结果,再赋值给j;
j=i++; //后置版本,先赋值给j;再运算对象自增1,但求值结果是运算对象改变之前那个值的副本.

2)拆分操作原则

对于一个可结合和可交换的合并操作来说,比如整数的加法或乘法,
我们可以通过将一组合并操作分割成 2 个或更多的部分,并在最后合并结果来提高性能。
原理:
普通代码只能利用 CPU 的一个寄存器,分割后可以利用多个寄存器。
当分割达到一个数量时,寄存器用完,性能不再提升,甚至会开始下降。
用代码来描述,如下:

// 一般情况下的代码 for (i = 1; i < n+1; i++)
{
    res = res OPER i;
}

// 循环分割后代码for (i = 1; i < n; i+=2)
{
    res1 = res1 OPER i;
    res2 = res2 OPER (i+1);
}
int 整数加法,性能测试结果对比如下:
整数的加法,普通代码运行 26s,循环分割后,18s。
浮点数计算的性能提升,明显大于整数,乘法的性能提升,略大于加法。

3)外小内大”原则

转自:https://blog.csdn.net/qq_44750696/article/details/121394877

嵌套循环应该遵循“外小内大”的原则,当需要嵌套循环时,尽可能让外层循环越小,性能越好;

long stratTime = System.nanoTime();
for (int i = 0; i < 10000000; i++) {
	for (int j = 0; j < 10; j++) {
 
	}
}
long endTime = System.nanoTime();
System.out.println("外大内小耗时:"+ (endTime - stratTime));


//改为

long stratTime = System.nanoTime();
for (int i = 0; i <10 ; i++) {
	for (int j = 0; j < 10000000; j++) {
 
	}
}
long endTime = System.nanoTime();
System.out.println("外小内大耗时:"+(endTime - stratTime));

两者对比: 

外大内小耗时:200192114  
外小内大耗时:97995997  

4)提取与循环无关的表达式

//代码中的a*b运算和循环是无关的,所以我们应该把他放到循环的外面,避免重复计算。
for (int i = 0; i < 10000000; i++) {
    i=i*a*b;
}

//应修改为:

c = a*b;
for (int i = 0; i < 10000000; i++) {
     i=i*c;
}

代码中的a*b运算和循环是无关的,所以我们应该把他放到循环的外面,避免重复计算,这可是不容忽视的效率问题 

5)消除循环终止判断时的方法调用

long stratTime = System.nanoTime();
for (int i = 0; i < list.size(); i++) {
 
}
long endTime = System.nanoTime();
System.out.println("未优化list耗时:"+(endTime - stratTime));

//应改为:

long stratTime = System.nanoTime();
int size = list.size();
for (int i = 0; i < size; i++) { 
}
long endTime = System.nanoTime();
System.out.println("优化list耗时:"+(endTime - stratTime));

两者耗时对比:
未优化list耗时:27375  
优化list耗时:2444 

list.size()每次循环都会被执行一次,这无疑会影响程序的性能,所以应该将其放到循环外面,用一个变量来代替,优化前后的对比也很明显。  

6)异常捕获

long stratTime = System.nanoTime();
for (int i = 0; i < 10000000; i++) {
	try {
	} catch (Exception e) {
	}
}
long endTime = System.nanoTime();
System.out.println("在内部捕获异常耗时:"+(endTime - stratTime));
//应改为:

long stratTime = System.nanoTime();
try {
     for (int i = 0; i < 10000000; i++) {
     }
} catch (Exception e) {
}
long endTime = System.nanoTime();
System.out.println("在外部捕获异常耗时:"+(endTime - stratTime));

 两者耗时对比:

在内部捕获异常耗时:12150142  
在外部捕获异常耗时:1955  
捕获异常是很耗资源的,所以不要把try catch放到循环内部,优化后同样有好几个数量级的提升。

7)尝试使用map结构查询的执行方式; 


for(Member m2:list2){
     if(m2.getName()==null){
         for(Member m1:list1){
              if(m1.getId().intValue()==m2.getId().intValue()){
                  System.out.println(m2.getId()+" Name 值为空!!!");
              }
         }
     }
}

//下边来看使用map代替的执行方式,以及两种方式的效率对比:
//map查询测试
 long s3 = System.currentTimeMillis();
   
 int mapNumber = 0;
 Map<Integer, Member> map = new HashMap<>();
 
 for(Member m1:list1){
      map.put(m1.getId(), m1);
 }
 
 for(Member m2:list2){
      if(m2.getName()==null){
          Member m = map.get(m2.getId());
          if(m!=null){
              System.out.println(m2.getId()+" Name 值为空!!!");
               mapNumber++;
          }
      }
 }

8)减少循环变量的实例化,比如:

for (int i = 0; i < 1000; i++){}

应改为:

int i, j, k;

for (i = 0; i < 10; i++){}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Nikola TesIa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值