分为分支优化循环优化分支 + 循环组合优化三大部分,全部贴合 JVM 底层执行原理,既有理论也有可直接落地的代码对比。

一、分支逻辑性能优化(if-else /switch)

1. 多分支优先使用 switch,替代多层 else if

底层原理:

  • if-else if:顺序逐个比较,匹配越靠后执行次数越多,时间复杂度 O (n);
  • switch(int/String/枚举):JVM 会生成跳转表 tableswitch/lookupswitch,直接寻址跳转,时间复杂度 O (1)。

适用场景:固定离散值匹配(菜单、状态码、类型标识) ❌ 低效多层 if

java

运行

int type = 2;
if(type == 1){
    method1();
}else if(type == 2){
    method2();
}else if(type == 3){
    method3();
}

✅ 高效 switch

java

运行

switch (type){
    case 1: method1(); break;
    case 2: method2(); break;
    case 3: method3(); break;
}

补充:Java 14+ 模式匹配 switch、箭头 switch 无 break,性能一致且更简洁。

2. if 判断条件:高频命中条件前置

else if 从上到下顺序判断,把最常满足的条件写在最前面,减少无效比较。 ❌ 反例(低频条件放前面)

java

运行

// 90%数据score>=90,却写在最后
if(score < 60){}
else if(score <80){}
else if(score <90){}
else{}

✅ 优化:高频条件前置

java

运行

if(score >=90){}
else if(score >=80){}
else if(score >=60){}
else{}

3. 合并重复判断,减少布尔运算

同一条件不要多次计算,提取局部变量缓存结果。 ❌ 重复计算

java

运行

if(user.getAge() > 18 && user.getAge() < 60){
    if(user.getAge() > 30){}
}

✅ 缓存一次

java

运行

int age = user.getAge();
if(age > 18 && age < 60){
    if(age > 30){}
}

4. 复杂多条件分支:用枚举 / 策略模式消除多层 if

分支超过 5 层,大量 if 会造成分支预测失效(CPU 分支缓存命中率下降)。 思路:把每个分支逻辑封装成策略类,用枚举映射执行逻辑,消除长 if 链。

5. 减少分支穿透,合理利用 case 穿透

不需要穿透时必须加 break;需要多值共用逻辑才主动省略 break,避免多余判断。

6. 避免循环内创建分支判断依赖对象

不要在 if 条件中频繁调用 IO、数据库、复杂计算方法,提前缓存结果。

二、循环逻辑性能优化(for/while/do-while,核心优化点)

1. 循环外提取不变计算,杜绝循环内重复运算

循环体中值永远不变的表达式、方法、对象创建全部提到循环外部。 ❌ 低效:每次循环都执行 length ()、new 对象

java

运行

String str = "abc123";
for(int i=0;i<str.length();i++){
    Date date = new Date();
}

✅ 优化:提前缓存

java

运行

String str = "abc123";
int len = str.length();
Date date = new Date();
for(int i=0;i<len;i++){}

2. 优先普通 for 循环,慎用增强 for、Stream(超大集合场景)

  • 普通 for:直接下标访问数组 / ArrayList,无迭代器创建开销;
  • 增强 for 底层创建 Iterator,小集合无感知,百万级数据有性能损耗;
  • Stream 流式循环存在拆箱、装箱、中间对象创建,纯遍历场景优先普通 for。

3. 控制循环嵌套层数,减少循环总次数

嵌套循环时间复杂度相乘:两层 for O (n²),数据量大时性能暴跌。 优化思路:

  1. 外层循环次数尽量小;
  2. 能通过 Map/Set 查表替代内层循环就替换; 示例:两层循环匹配数据 → 先把数据存入 HashMap,一次遍历查表。

❌ 双重循环匹配

java

运行

List<User> userList = ...;
List<Order> orderList = ...;
for(User u : userList){
    for(Order o : orderList){
        if(o.getUid().equals(u.getId())){}
    }
}

✅ Map 查表,降复杂度 O (n+m)

java

运行

Map<Long,User> userMap = new HashMap<>();
userList.forEach(u->userMap.put(u.getId(),u));
for(Order o : orderList){
    User u = userMap.get(o.getUid());
}

4. 循环变量优化:减少自增、类型转换开销

  1. 使用 int 代替 long、double 做循环下标;
  2. 避免循环内强转类型;
  3. 倒序循环有时性能更好(部分 JVM 优化边界判断): for(int i=arr.length-1;i>=0;i--)

5. 减少循环内对象创建,降低 GC 压力

循环中 new 对象会产生大量临时垃圾,频繁触发 GC 卡顿:

  1. 可复用对象提前 new,循环内只修改属性;
  2. 基础类型优先用局部变量,避免包装类频繁装箱拆箱。

❌ 循环内频繁创建包装类

java

运行

for(int i=0;i<10000;i++){
    Integer num = Integer.valueOf(i);
}

✅ 复用基础类型

java

运行

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

6. 合理使用 break/continue,提前终止无效循环

满足目标条件立刻 break,不要完整遍历全部数据。 示例:查找指定元素,找到直接跳出循环。

7. 死循环 while (true) 必须设置退出条件

无出口死循环占用 CPU,业务死循环搭配 sleep/break 降低空转消耗。

三、分支 + 循环组合场景专项优化(业务最常用)

1. 循环内多层 if:将判断提取到循环外

如果整个循环只有两种分支逻辑,拆分两次循环,不要在循环内部 if 判断。 ❌ 循环内分支判断

java

运行

for(Item item : list){
    if(type == 1){
        handleType1(item);
    }else{
        handleType2(item);
    }
}

✅ 提前分组,分两次循环

java

运行

List<Item> list1 = new ArrayList<>();
List<Item> list2 = new ArrayList<>();
list.forEach(i->{
    if(i.getType()==1) list1.add(i);
    else list2.add(i);
});
list1.forEach(this::handleType1);
list2.forEach(this::handleType2);

2. 循环内 switch:缓存匹配值,减少重复取值

java

运行

// 优化前:每次case都调用getType()
for(Order o : orders){
    switch (o.getType()){...}
}
// 优化后:一次取值
for(Order o : orders){
    int type = o.getType();
    switch (type){...}
}

3. 减少循环嵌套中的分支深度

嵌套超过 2 层时,抽取分支逻辑为独立方法,降低 CPU 分支预测失败概率。CPU 遇到大量随机分支会丢弃流水线指令,大幅降低执行速度。

四、JVM 层面隐藏优化点

  1. 分支预测:分支条件稳定(大部分走同一个分支)性能极高;分支结果随机(一半 true 一半 false)性能暴跌,这种场景尽量用查表、数组映射替代 if。
  2. 循环展开:JIT 编译器会自动优化短循环(循环次数固定、次数少),人工无需干预;超长循环可手动拆分减少循环次数。
  3. 局部变量缓存:方法内局部变量存储在栈,访问速度远快于对象成员变量,循环内尽量用局部变量缓存对象属性。

五、优化优先级总结(实操落地顺序)

  1. 降复杂度:双层循环改用 Map/Set 查表(收益最大)
  2. 提取循环外不变计算、对象创建
  3. 多层 if 替换 switch / 策略模式
  4. 高频条件前置,减少布尔判断次数
  5. 复用对象,避免循环内频繁 new,减少 GC
  6. 拆分循环内分支,消除多层嵌套
  7. 普通 for 替代增强 for/Stream 超大集合遍历
  8. 合理 break 提前终止循环,减少循环总次数

更多推荐