for循环优化方式有哪些?

前言

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

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

代码语言:javascript

Cloud Studio代码运行

ini 复制代码
List<String> list = new ArrayList<>();

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

代码语言:javascript

Cloud Studio代码运行

css 复制代码
for (int i = 0; i < list.size(); i++) {
    System.out.println(list.get(i));
}
  • 优点:较常见,易于理解
  • 缺点:每次都要计算 list.size()

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

代码语言:javascript

Cloud Studio代码运行

ini 复制代码
int size = list.size();

for (int i = 0; i < size; i++) {
    System.out.println(list.get(i));
}
  • 优点:不必每次都计算 list.size()

  • 缺点:

    • size 的作用域不够小,违反了最小作用域原则
    • 不能在 for 循环中操作 list 的大小,比如除去或新加一个元素

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

代码语言:javascript

Cloud Studio代码运行

css 复制代码
for (int i = 0, size = list.size(); i < size; i++) {
    System.out.println(list.get(i));
}
  • 优点:不必每次都计算,变量的作用域遵循最小范围原则

  • 缺点:

    • size 的作用域不够小,违反了最小作用域原则
    • 不能在 for 循环中操作 list 的大小,比如除去或新加一个元素

方法四:采用倒序的写法

代码语言:javascript

Cloud Studio代码运行

css 复制代码
for (int i = list.size() - 1; i >= 0; i--) {
    System.out.println(list.get(i));
}
  • 优点:不必每次都计算,变量的作用域遵循最小范围原则

  • 缺点:

    • 1、结果的顺序会反
    • 2、看起来不习惯,不易读懂
  • 适用场合:与显示结果顺序无关的地方:比如保存之前数据的校验

方法五:Iterator 遍历

代码语言:javascript

代码运行次数:0

Cloud Studio代码运行

ini 复制代码
for (Iterator<String> it = list.iterator(); it.hasNext(); ) {
    System.out.println(it.next());
}
  • 优点:简洁

方法六:jdk 1.5 后的写法

代码语言:javascript

代码运行次数:0

Cloud Studio代码运行

scss 复制代码
for (String o : list) {
    System.out.println(o);
}
  • 优点:简洁, 结合泛型使用更简洁
  • 缺点:jdk 1.4 向下不兼容(也就是 < 1.5 版本就不能这么写)

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

代码语言:javascript

代码运行次数:0

Cloud Studio代码运行

ini 复制代码
for (int i = 0; i < 10; i++) {
    for (int j = 0; j < 10000; j++) {
    }
}

原因

分支优化规则

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

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

代码语言:javascript

Cloud Studio代码运行

ini 复制代码
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]++;
    }
}

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

代码语言:javascript

Cloud Studio代码运行

ini 复制代码
// 前:
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;
}

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

反例:

代码语言:javascript

Cloud Studio代码运行

php 复制代码
for (int i = 0; i < 10; i++) {
    try {

    } catch (Exception e) {

    }
}

正例:

代码语言:javascript

Cloud Studio代码运行

php 复制代码
try {
    for (int i = 0; i < 10; i++) {
    }
} catch (Exception e) {

}
相关推荐
Gopher_HBo5 小时前
Go CPU 剖析的"地基":信号、CAS、写屏障、无锁环形缓冲
后端
panbook5 小时前
从0到1实现一个分布式时序数据库(二):写入成功之后,如何用 WAL 找回数据
后端
Swot5 小时前
上传一张 4MB 图片,我先后撞上了三层请求体限制
后端
IT_陈寒5 小时前
Vite的HMR把我整不会了:一个生产环境的热更新坑
前端·人工智能·后端
OLRainM5 小时前
实习复盘:大模型网关渠道质量评分实战(二)—— 报错了到底算谁的锅?流式归因与 Token 补账踩过的 8 个真坑
后端
梦想恒远6 小时前
Spring Boot + LangChain4j 统计 token 成本:ChatModelListener 实测与单价口径
spring boot·后端
努力的小郑7 小时前
数据查到了,回答去哪儿了?一次百炼 + LangChain 排查实录
后端·langchain·agent
新*7 小时前
从一段 WebSocket 代码聊开:bytes 不是 zlib、binaryType 决定一切,15MB 大消息的零拷贝优化
javascript·python·websocket·性能优化·blob·zlib·arraybuffer
isfox7 小时前
Python 虚拟环境:别再把所有项目塞进一个"大仓库"了
后端
易师傅8 小时前
技术面试已死?AI 时代,真正拉开程序员差距的是什么?
前端·后端·程序员