常见的for循环优化方式

简介: 经常使用一些循环,进行耗时计算的操作,特别是 for 循环,它是一种重复计算的操作,如果处理不好,耗时就比较大,如果处理书写得当,将大大提高效率,下面总结几条 for 循环的常见优化方式。

?> 前言


经常使用一些循环,进行耗时计算的操作,特别是 for 循环,它是一种重复计算的操作,如果处理不好,耗时就比较大,如果处理书写得当,将大大提高效率,下面总结几条 for 循环的常见优化方式。


首先初始化一个集合 list,如下:

List<String> list = new ArrayList<>();


方式一:最常规的不加思考的写法

for (int i = 0; i < list.size(); i++) {
    System.out.println(list.get(i));
}


  • 优点:较常见,易于理解
  • 缺点:每次都要计算 list.size()


方式二:数组长度提取出来

int size = list.size();
for (int i = 0; i < size; i++) {
    System.out.println(list.get(i));
}


  • 优点:不必每次都计算 list.size()
  • 缺点:
  • size 的作用域不够小,违反了最小作用域原则
  • 不能在 for 循环中操作 list 的大小,比如除去或新加一个元素


方法三:数组长度提取出来

for (int i = 0, size = list.size(); i < size; i++) {
    System.out.println(list.get(i));
}


  • 优点:不必每次都计算,变量的作用域遵循最小范围原则
  • 缺点:
  • size 的作用域不够小,违反了最小作用域原则
  • 不能在 for 循环中操作 list 的大小,比如除去或新加一个元素


方法四:采用倒序的写法

for (int i = list.size() - 1; i >= 0; i--) {
    System.out.println(list.get(i));
}


  • 优点:不必每次都计算,变量的作用域遵循最小范围原则
  • 缺点:
  • 1、结果的顺序会反
  • 2、看起来不习惯,不易读懂
  • 适用场合:与显示结果顺序无关的地方:比如保存之前数据的校验


方法五:Iterator 遍历

for (Iterator<String> it = list.iterator(); it.hasNext(); ) {
    System.out.println(it.next());
}


  • 优点:简洁


方法六:jdk 1.5 后的写法

for (String o : list) {
    System.out.println(o);
}


  • 优点:简洁, 结合泛型使用更简洁
  • 缺点:jdk 1.4 向下不兼容(也就是 < 1.5 版本就不能这么写)


方法七:循环嵌套外小内大原则

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


原因


?> 分支优化规则


引入流水线工作机制以后,为了配合流水线工作,处理器增加了一个分支目标缓冲器(Branch Target Buffer)。在流水线工作模式下,如果遇到分支结构,就可以利用分支目标缓冲器预测并读取指令的目标地址。分支目标缓冲器在程序运行时将动态记录和调整转移指令的目标地址,可以记录多个地址,对其进行表格化管理。当发生转移时,如果分支目标缓冲器中有记录,下一条指令在取指令阶段就会将其作为目标地址。如果记录地址等于实际目标地址,则并行成功;如果记录地址不等于实际目标地址,则流水线被冲洗。同一个分支,多次预测失败,则更新记录的目标地址。因此,分支预测属于 “经验主义” 或 “机会主义",会存在一定的误测。


基于上述原因,大家以后在编写多重循环时应该把大循环放到内层,这样可以增加分支预测的准确度,如下面的示例所示:

int[][] a = new int[10][10000];
for (int i = 0; i < 10; i++) {
    // 下面每次循环会预测成功9999次
    // 第1次没有预测,最后退出循环时预测失败1次这样的
    // 过程重复10次
    for (int j = 0; j < 10000; j++) {
        a[i][j]++;
    }
}
for (int j = 0; j < 10000; j++) {
    // 下面每次循环会预测成功9次
    // 第1次没有预测,最后退出循环时预测失败1次
    // 这样的过程重复10000次
    for (int i = 0; i < 10; i++) {
        a[i][j]++;
    }
}


方法八:循环嵌套提取不需要循环的逻辑

/ 前:
int a = 10, b = 11;
for (int i = 0; i < 10; i++) {
    i = i * a * b;
}
// 后:
int c = a * b;
for (int i = 0; i < 10; i++) {
    i = i * c;
}


方法九:异常处理写在循环外面


反例:

for (int i = 0; i < 10; i++) {
    try {
    } catch (Exception e) {
    }
}


正例:

try {
    for (int i = 0; i < 10; i++) {
    }
} catch (Exception e) {
}
目录
相关文章
|
监控 流计算
【极数系列】Flink集成DataSource读取文件数据(08)
【极数系列】Flink集成DataSource读取文件数据(08)
180 2
|
编译器 C语言 C++
右值引用,完美转发,NRVO 和RVO优化(简单易懂详细)
右值引用,完美转发,NRVO 和RVO优化(简单易懂详细)
1355 0
|
缓存 Android开发
Android Studio中如何清理gradle缓存
Android Studio中如何清理gradle缓存
|
5月前
|
JSON API 数据格式
手把手教你抓取京东商品评论:API 接口解析与 Python 实战
京东商品评论蕴含用户对产品质量、体验和服务的真实反馈,分析这些数据有助于企业优化产品和满足用户需求。由于京东未提供官方API,需通过逆向工程获取评论数据。其主要接口为“商品评论列表接口”,支持按商品ID、评分、排序方式等参数获取评论,返回JSON格式数据,包含评论列表、摘要(如好评率)及热门标签等信息。
|
12月前
|
Kubernetes 持续交付 Docker
利用 Docker 和 Kubernetes 实现微服务部署
【10月更文挑战第2天】利用 Docker 和 Kubernetes 实现微服务部署
|
JavaScript
成功解决:Failed to resolve directive: mode
这篇文章介绍了如何解决Vue中遇到的"Failed to resolve directive: mode"错误的两个常见原因及其解决办法:确保指令的单词拼写正确,以及在创建Vue实例之前注册全局指令。
成功解决:Failed to resolve directive: mode
|
存储 安全 Java
CopyOnWriteArrayList底层原理全面解析【建议收藏】
CopyOnWriteArrayList是Java中的一个线程安全的集合类,是ArrayList线程安全版本,主要通过Copy-On-Write(写时复制,简称COW)机制来保证线程安全。 Copy-On-Write机制核心思想:向一个数组中添加数据时,不直接操作原始数组,而是拷贝原始数组生成一份原始数组副本,将需要添加的数据添加到原始数组副本中,操作完成后再用原始数组副本直接替换原始数组,从而保证多个线程同时操作原始数组时的线程安全。
|
存储 Python 容器
`click`是一个用于构建命令行接口的Python包,它提供了简单、可组合的命令行解析器。
`click`是一个用于构建命令行接口的Python包,它提供了简单、可组合的命令行解析器。
|
SQL Java 数据库连接
对 MyBatis Plus SaveBatch 调优提升25倍性能!!!
最近在压测一批接口,发现接口处理速度慢的有点超出预期,感觉很奇怪,后面定位发现是数据库批量保存这块很慢。这个项目用的是,批量保存直接用的是提供的 saveBatch。于是开始排查之路。所以如果有使用 jdbc 的 Batch 性能方面的需求,要将rewriteBatchedStatements 设置为 true,这样能提高很多性能。然后如果喜欢手动拼接 sql 要注意一次拼接的数量,分批处理。
834 1
|
安全 Java 数据库
Spring Security自定义登录认证
Spring Security自定义登录认证
543 0