代码高效简洁之道(循环优化 )

19 篇文章 0 订阅

循环在Java里是不可避免也是经常使用到的,循环一个数组集合非常常用。如何写一个安全简洁高效的循环呢?

  • 循环无关代码外提:是指在一个循环里不发生改变的表达式比如数组长度,当然这是要不影响整个循环的语义。

int foo(int x, int y, int[] a) {
  int sum = 0;
  for (int i = 0; i < a.length; i++) {
    sum += x * y + a[i];
  }
  return sum;
}
  • 在上文这个示例里,让我们看一下那些是没有在循环里发生改变的。

  • 首先很明显a.length在每次循环都是不变的值。

  • 其次是x*y 的值也没有发生改变。那就可以做一次优化.

    int  foo(int x,int y,int[] a){
        int sum=x*y;
        for(int i=0 ,len=a.length;i<len;i++)
        {
            sum+=a[i]
        }
        return sum;
    }
    

     

  • 这是代码层面所做的优化,编译器能够如何进一步优化呢?

  • int 数组加载指令iaload 的null 检测及数组越界检测(range check)。数组和下标作为参数,伪代码如下
int iaload(int[] a,int i){
    
    if(null==a){
        throw new NullException();  
    }
    if(i<0||i>=a.length){
        throw new ArrayIndexOutOfBoundsException();
    }
    return a[i]
}
  • null 检测外提优化,是C2即时编译器通过循环预测来进行优化。即在循环外进行null 检测,命中测可消除循环内的null检测。

  • 数组越界检测则是通过检测i的最小值和i的最大值和数组长度比较进行外提到循环外。i能达到的最大值不一定等于数组长度减一,这是因为步长,即i++可能是i+2,也可能在循环内改变i的值。伪代码

    // in能达到的最大值MAX,len数组长度
    if(i<0||MAX>=len){
          throw  new IndexOutOfBoundsException();
    }
    
    for...

     

循环展开是另一项循环优化方式:即对循环的次数进行进行一定次的展开。一个示例:

int foo(int[] a) {
  int sum = 0;
  for (int i = 0; i < 64; i++) {
    sum += (i % 2 == 0) ? a[i] : -a[i];
  }
  return sum;
}
  • 对上述循环进行一次展开,明显减少了循环次数,减少了一半。
int foo(int[] a) {
  int sum = 0;
  for (int i = 0; i < 64; i+=2) {
    sum += (i % 2 == 0) ? a[i] : -a[i];
    sum+=((i+1)%2==0)?a[i+1]:-a[i+1]
  }
  return sum;
}
  • 进一步可以优化为:很明显i从0 开始,每次加2,则i%2 每次都是0,(i+1)%2 则都是1
int foo(int[] a) {
  int sum = 0;
  for (int i = 0; i < 64; i+=2) {
    sum += a[i] 
    sum +=-a[i+1]
  }
  return sum;
}
  • 循环完全展开,如果循环的次数比较小,则可以进行完全展开。即不适用循环。

  • 循环判断外提 :也可以进行优化循环,循环里的判断放在循环外进行。

    int foo(int[] a) {
      int sum = 0;
      for (int i = 0; i < a.length; i++) {
        if (a.length > 4) {
          sum += a[i];
        }
      }
      return sum;
    }
    

     

  • 外提后优化

    int foo(int[] a) {
      int sum = 0;
     if (a.length > 4) {
      for (int i = 0; i < a.length; i++) {
          sum += a[i];
        }
      }
      return sum;
    }
    

     

  • 循环剥离  就是将循环里的几个特殊迭代进行剥离。

    int foo(int[] a) {
      int sum = 0;
    
      if(0<a.length){
          sum = a[0];
        
      for (int i = 1; i < a.length; i++) {
          sum += a[i];
        }
      }
      return sum;
    }

    本文参考自循环优化 2018-09-17 郑雨迪

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值