信息发布→ 登录 注册 退出

java实战技巧之if-else代码优化技巧大全

发布时间:2026-01-11

点击量:
目录
  • 前言
  • 技巧一:提取方法,拆分逻辑
  • 技巧二:分支逻辑提前return
  • 技巧三:枚举
  • 技巧四:函数式接口
  • 技巧五:设计模式
    • 使用技巧一:工厂模式+抽象类
    • 使用技巧二:策略模式+模板方法+工厂模式+单例模式
  • 其他技巧
    • 写在最后

      前言

      在实际的业务开发当中,经常会遇到复杂的业务逻辑,可能部分同学实现出来的代码并没有什么问题,但是代码的可读性很差。本篇文章主要总结一下自己在实际开发中如何避免大面积的 if-else 代码块的问题。补充说明一点,不是说 if-else 不好,而是多层嵌套的 if-else 导致代码可读性差、维护成本高等问题。

      现有如下一段示例代码,部分优化技巧是根据这段代码进行的

      public class BadCodeDemo {
          private void getBadCodeBiz(Integer city, List<TestCodeData> newDataList, List<TestCodeData> oldDataList) {
              if (city != null) {
      
                  if (newDataList != null && newDataList.size() > 0) {
                      TestCodeData newData = newDataList.stream().filter(p -> {
                          if (p.getIsHoliday() == 1) {
                              return true;
                          }
                          return false;
                      }).findFirst().orElse(null);
                      if (newData != null) {
                          newData.setCity(city);
                      }
                  }
      
              } else {
      
                  if (oldDataList != null && newDataList != null) {
                      List<TestCodeData> oldCollect = oldDataList.stream().filter(p -> {
                          if (p.getIsHoliday() == 1) {
                              return true;
                          }
                          return false;
      
                      }).collect(Collectors.toList());
                      List<TestCodeData> newCollect = newDataList.stream().filter(p -> {
                          if (p.getIsHoliday() == 1) {
                              return true;
                          }
                          return false;
                      }).collect(Collectors.toList());
      
                      if (newCollect != null && newCollect.size() > 0 && oldCollect != null && oldCollect.size() > 0) {
                          for (TestCodeData newPO : newCollect) {
                              if (newPO.getStartTime() == 0 && newPO.getEndTime() == 12) {
                                  TestCodeData po = oldCollect.stream().filter(p -> p.getStartTime() == 0
                                          && (p.getEndTime() == 12 || p.getEndTime() == 24)).findFirst().orElse(null);
                                  if (po != null) {
                                      newPO.setCity(po.getCity());
                                  }
                              } else if (newPO.getStartTime() == 12 && newPO.getEndTime() == 24) {
                                  TestCodeData po = oldCollect.stream().filter(
                                          p -> (p.getStartTime() == 12 || p.getStartTime() == 0)
                                                  && p.getEndTime() == 24).findFirst().orElse(null);
                                  if (po != null) {
                                      newPO.setCity(po.getCity());
                                  }
                              } else if (newPO.getStartTime() == 0 && newPO.getEndTime() == 24) {
                                  TestCodeData po = oldCollect.stream().filter(
                                          p -> p.getStartTime() == 0 && p.getEndTime() == 24).findFirst().orElse(null);
                                  if (po == null) {
                                      po = oldCollect.stream().filter(
                                              p -> p.getStartTime() == 0 && p.getEndTime() == 12).findFirst().orElse(null);
                                  }
                                  if (po == null) {
                                      po = oldCollect.stream().filter(
                                              p -> p.getStartTime() == 12 && p.getEndTime() == 24).findFirst().orElse(null);
                                  }
                                  if (po != null) {
                                      newPO.setCity(po.getCity());
                                  }
                              } else if (newPO.getTimeUnit().equals(Integer.valueOf(1))) {
                                  TestCodeData po = oldCollect.stream().filter(
                                          e -> e.getTimeUnit().equals(Integer.valueOf(1))).findFirst().orElse(null);
                                  if (po != null) {
                                      newPO.setCity(po.getCity());
                                  }
                              }
                          }
                      }
      
                  }
              }
          }
      }

      技巧一:提取方法,拆分逻辑

      比如上面这段代码中

      if(null != city) {
      } else {
      }

      这里可以拆分成两段逻辑,核心思想就是逻辑单元最小化,然后合并逻辑单元。

      private void getCityNotNull(Integer city, List<TestCodeData> newDataList) {
          if (newDataList != null && newDataList.size() > 0) {
              TestCodeData newData = newDataList.stream().filter(p -> {
                  if (p.getIsHoliday() == 1) {
                      return true;
                  }
                  return false;
              }).findFirst().orElse(null);
              if (newData != null) {
                  newData.setCity(city);
              }
          }
      }
      
      // 合并逻辑流程
      private void getBadCodeBiz(Integer city, List<TestCodeData> newDataList, List<TestCodeData> oldDataList) {
          if (city != null) {
              this.getCityNull(city, newDataList);
          } else {
              //此处代码省略
          }
      }

      技巧二:分支逻辑提前return

      比如 技巧一 中的 getCityNull 方法,我们可以这样写

      public void getCityNotNull(Integer city, List<TestCodeData> newDataList) {
          if (CollectionUtils.isEmpty(newDataList)) {
              // 提前判断,返回业务逻辑
              return;
          }
          TestCodeData newData = newDataList.stream().filter(p -> {
              if (p.getIsHoliday() == 1) {
                  return true;
              }
              return false;
          }).findFirst().orElse(null);
          
          if (null != newData) {
              newData.setCity(city);
          }
      }

      技巧三:枚举

      经过 技巧一技巧二 的优化,文章开头的这段代码被优化成如下所示:

      public class BadCodeDemo {
          public void getBadCodeBiz(Integer city, List<TestCodeData> newDataList, List<TestCodeData> oldDataList) {
              if (city != null) {
                  this.getCityNotNull(city, newDataList);
              } else {
                  this.getCityNull(newDataList, oldDataList);
              }
          }
      
          private void getCityNotNull(Integer city, List<TestCodeData> newDataList) {
              if (CollectionUtils.isEmpty(newDataList)) {
                  // 提前判断,返回业务逻辑
                  return;
              }
              TestCodeData newData = newDataList.stream().filter(p -> {
                  if (p.getIsHoliday() == 1) {
                      return true;
                  }
                  return false;
              }).findFirst().orElse(null);
      
              if (null != newData) {
                  newData.setCity(city);
              }
          }
      
          private void getCityNull(List<TestCodeData> newDataList, List<TestCodeData> oldDataList) {
              // 提前判断,返回业务逻辑
              if (CollectionUtils.isEmpty(oldDataList) && CollectionUtils.isEmpty(newDataList)) {
                  return;
              }
      
              List<TestCodeData> oldCollect = oldDataList.stream().filter(p -> {
                  if (p.getIsHoliday() == 1) {
                      return true;
                  }
                  return false;
              }).collect(Collectors.toList());
      
              List<TestCodeData> newCollect = newDataList.stream().filter(p -> {
                  if (p.getIsHoliday() == 1) {
                      return true;
                  }
                  return false;
              }).collect(Collectors.toList());
      
              // 提前判断,返回业务逻辑
              if (CollectionUtils.isEmpty(newCollect) && CollectionUtils.isEmpty(oldCollect)) {
                  return;
              }
      
              for (TestCodeData newPO : newCollect) {
                  if (newPO.getStartTime() == 0 && newPO.getEndTime() == 12) {
                      TestCodeData po = oldCollect.stream().filter(p -> p.getStartTime() == 0
                              && (p.getEndTime() == 12 || p.getEndTime() == 24)).findFirst().orElse(null);
                      if (po != null) {
                          newPO.setCity(po.getCity());
                      }
                  } else if (newPO.getStartTime() == 12 && newPO.getEndTime() == 24) {
                      TestCodeData po = oldCollect.stream().filter(
                              p -> (p.getStartTime() == 12 || p.getStartTime() == 0)
                                      && p.getEndTime() == 24).findFirst().orElse(null);
                      if (po != null) {
                          newPO.setCity(po.getCity());
                      }
                  } else if (newPO.getStartTime() == 0 && newPO.getEndTime() == 24) {
                      TestCodeData po = oldCollect.stream().filter(
                              p -> p.getStartTime() == 0 && p.getEndTime() == 24).findFirst().orElse(null);
                      if (po == null) {
                          po = oldCollect.stream().filter(
                                  p -> p.getStartTime() == 0 && p.getEndTime() == 12).findFirst().orElse(null);
                      }
                      if (po == null) {
                          po = oldCollect.stream().filter(
                                  p -> p.getStartTime() == 12 && p.getEndTime() == 24).findFirst().orElse(null);
                      }
                      if (po != null) {
                          newPO.setCity(po.getCity());
                      }
                  } else if (newPO.getTimeUnit().equals(Integer.valueOf(1))) {
                      TestCodeData po = oldCollect.stream().filter(
                              e -> e.getTimeUnit().equals(Integer.valueOf(1))).findFirst().orElse(null);
                      if (po != null) {
                          newPO.setCity(po.getCity());
                      }
                  }
              }
          }
      }

      现在利用 枚举 来优化 getCityNull 方法中的 for 循环部分代码,我们可以看到这段代码中有4段逻辑,总体形式如下:

      if (newPO.getStartTime() == 0 && newPO.getEndTime() == 12) {
          //第一段逻辑
      } else if (newPO.getStartTime() == 12 && newPO.getEndTime() == 24) {
          //第二段逻辑
      } else if (newPO.getStartTime() == 0 && newPO.getEndTime() == 24) {
          //第三段逻辑
      } else if (newPO.getTimeUnit().equals(Integer.valueOf(1))) {
          //第四段逻辑
      }    

      按照这个思路利用枚举进行二次优化,将其中的逻辑封装到枚举类中:

      public enum TimeEnum {
          AM("am", "上午") {
              @Override
              public void setCity(TestCodeData data, List<TestCodeData> oldDataList) {
                  TestCodeData po = oldDataList.stream().filter(p -> p.getStartTime() == 0
                          && (p.getEndTime() == 12 || p.getEndTime() == 24)).findFirst().orElse(null);
                  if (null != po) {
                      data.setCity(po.getCity());
                  }
              }
          },
          PM("pm", "下午") {
              @Override
              public void setCity(TestCodeData data, List<TestCodeData> oldCollect) {
                  TestCodeData po = oldCollect.stream().filter(
                          p -> (p.getStartTime() == 12 || p.getStartTime() == 0)
                                  && p.getEndTime() == 24).findFirst().orElse(null);
                  if (po != null) {
                      data.setCity(po.getCity());
                  }
              }
          },
          DAY("day", "全天") {
              @Override
              public void setCity(TestCodeData data, List<TestCodeData> oldCollect) {
                  TestCodeData po = oldCollect.stream().filter(
                          p -> p.getStartTime() == 0 && p.getEndTime() == 24).findFirst().orElse(null);
                  if (po == null) {
                      po = oldCollect.stream().filter(
                              p -> p.getStartTime() == 0 && p.getEndTime() == 12).findFirst().orElse(null);
                  }
                  if (po == null) {
                      po = oldCollect.stream().filter(
                              p -> p.getStartTime() == 12 && p.getEndTime() == 24).findFirst().orElse(null);
                  }
                  if (po != null) {
                      data.setCity(po.getCity());
                  }
              }
          },
          HOUR("hour", "小时") {
              @Override
              public void setCity(TestCodeData data, List<TestCodeData> oldCollect) {
                  TestCodeData po = oldCollect.stream().filter(
                          e -> e.getTimeUnit().equals(Integer.valueOf(1))).findFirst().orElse(null);
                  if (po != null) {
                      data.setCity(po.getCity());
                  }
              }
          };
      
          public abstract void setCity(TestCodeData data, List<TestCodeData> oldCollect);
      
          private String code;
          private String desc;
      
          TimeEnum(String code, String desc) {
              this.code = code;
              this.desc = desc;
          }
      
          public String getCode() {
              return code;
          }
      
          public void setCode(String code) {
              this.code = code;
          }
      
          public String getDesc() {
              return desc;
          }
      
          public void setDesc(String desc) {
              this.desc = desc;
          }
      }

      然后 getCityNull 方法中 for 循环部分逻辑如下:

      for (TestCodeData data : newCollect) {
          if (data.getStartTime() == 0 && data.getEndTime() == 12) {
              TimeEnum.AM.setCity(data, oldCollect);
          } else if (data.getStartTime() == 12 && data.getEndTime() == 24) {
              TimeEnum.PM.setCity(data, oldCollect);
          } else if (data.getStartTime() == 0 && data.getEndTime() == 24) {
              TimeEnum.DAY.setCity(data, oldCollect);
          } else if (data.getTimeUnit().equals(Integer.valueOf(1))) {
              TimeEnum.HOUR.setCity(data, oldCollect);
          }
      }

      其实在这个业务场景中使用枚举并不是特别合适,如果在遍历对象时,我们就知道要执行哪个枚举类型,此时最合适,伪代码如下:

      for (TestCodeData data : newCollect) {
            String code = "am";  // 这里假设 code 变量是从 data 中获取的
            TimeEnum.valueOf(code).setCity(data, oldCollect);
      }

      技巧四:函数式接口

      业务场景描述:比如让你做一个简单的营销拉新活动,这个活动投放到不同的渠道,不同渠道过来的用户奖励不一样。现假设在 头条、微信 等渠道都投放了该活动。此时你的代码可能会写出如下形式:

      @RestController
      @RequestMapping("/activity")
      public class ActivityController {
          @Resource
          private AwardService awardService;
      
          @PostMapping("/reward")
          public void reward(String userId, String source) {
              if ("toutiao".equals(source)) {
                  awardService.toutiaoReward(userId);
              } else if ("wx".equals(source)) {
                  awardService.wxReward(userId);
              }
          }
      }
      
      @Service
      public class AwardService {
          private static final Logger log = LoggerFactory.getLogger(AwardService.class);
      
          public Boolean toutiaoReward(String userId) {
              log.info("头条渠道用户{}奖励50元红包!", userId);
              return Boolean.TRUE;
          }
      
          public Boolean wxReward(String userId) {
              log.info("微信渠道用户{}奖励100元红包!", userId);
              return Boolean.TRUE;
          }
      }

      看完这段代码,逻辑上是没有什么问题的。但它有一个隐藏的缺陷,如果后期又增加很多渠道的时候,你该怎么办?继续 else if 吗?其实我们可以利用函数式接口优化,当然设计模式也可以优化。这里我只是举例使用一下函数式接口的使用方式。

      @RestController
      @RequestMapping("/activity")
      public class ActivityController {
          @Resource
          private AwardService awardService;
      
          @PostMapping("/reward")
          public void reward(String userId, String source) {
              awardService.getRewardResult(userId, source);
          }
      }
      
      @Service
      public class AwardService {
          private static final Logger log = LoggerFactory.getLogger(AwardService.class);
          private Map<String, BiFunction<String, String, Boolean>> sourceMap = new HashMap<>();
      
          @PostConstruct
          private void dispatcher() {
              sourceMap.put("wx", (userId, source) -> this.wxReward(userId));
              sourceMap.put("toutiao", (userId, source) -> this.toutiaoReward(userId));
          }
      
          public Boolean getRewardResult(String userId, String source) {
              BiFunction<String, String, Boolean> result = sourceMap.get(source);
              if (null != result) {
                  return result.apply(userId, source);
              }
              return Boolean.FALSE;
          }
      
          private Boolean toutiaoReward(String userId) {
              log.info("头条渠道用户{}奖励50元红包!", userId);
              return Boolean.TRUE;
          }
      
          private Boolean wxReward(String userId) {
              log.info("微信渠道用户{}奖励100元红包!", userId);
              return Boolean.TRUE;
          }
      }

      针对一些复杂的业务场景,业务参数很多时,可以利用 @FunctionalInterface 自定义函数式接口来满足你的业务需求,使用原理和本例并无差别。

      技巧五:设计模式

      设计模式对于if-else的优化,我个人觉得有些重,但是也是一种优化方式。设计模式适合使用在大的业务流程和场景中使用,针对代码块中的if-else逻辑优化不推荐使用。

      常用的设计模式有:

      • 策略模式
      • 模板方法
      • 工厂模式
      • 单例模式

      还是以上面的营销拉新活动为例来说明如何使用。

      使用技巧一:工厂模式+抽象类

      • 定义抽象业务接口
      public abstract class AwardAbstract {
          public abstract Boolean award(String userId);
      }
      • 定义具体业务实现类
      // 头条渠道发放奖励业务
      public class TouTiaoAwardService extends AwardAbstract {
          @Override
          public Boolean award(String userId) {
              log.info("头条渠道用户{}奖励50元红包!", userId);
              return Boolean.TRUE;
          }
      }
      
      // 微信渠道发放奖励业务
      public class WeChatAwardService extends AwardAbstract {
          @Override
          public Boolean award(String userId) {
              log.info("微信渠道用户{}奖励100元红包!", userId);
              return Boolean.TRUE;
          }
      }
      • 利用工厂模式获取实例对象
      public class AwardFactory {
          public static AwardAbstract getAwardInstance(String source) {
              if ("toutiao".equals(source)) {
                  return new TouTiaoAwardService();
              } else if ("wx".equals(source)) {
                  return new WeChatAwardService();
              }
              return null;
          }
      }
      • 业务入口处根据不同渠道执行不同的发放逻辑
      @PostMapping("/reward2")
      public void reward2(String userId, String source) {
          AwardAbstract instance = AwardFactory.getAwardInstance(source);
          if (null != instance) {
              instance.award(userId);
          }
      }

      使用技巧二:策略模式+模板方法+工厂模式+单例模式

      还是以营销拉新为业务场景来说明,这个业务流程再增加一些复杂度,比如发放奖励之前要进行 身份验证、风控验证 等一些列的校验,此时你的业务流程该如何实现更清晰简洁呢!

      • 定义业务策略接口
      /** 策略业务接口 */
      public interface AwardStrategy {
          /**
           * 奖励发放接口
           */
          Map<String, Boolean> awardStrategy(String userId);
      
          /**
           * 获取策略标识,即不同渠道的来源标识
           */
          String getSource();
      }
      • 定义奖励发放模板流程
      public abstract class BaseAwardTemplate {
          private static final Logger log = LoggerFactory.getLogger(BaseAwardTemplate.class);
      
          //奖励发放模板方法
          public Boolean awardTemplate(String userId) {
              this.authentication(userId);
              this.risk(userId);
              return this.awardRecord(userId);
          }
      
          //身份验证
          protected void authentication(String userId) {
              log.info("{} 执行身份验证!", userId);
          }
      
          //风控
          protected void risk(String userId) {
              log.info("{} 执行风控校验!", userId);
          }
      
          //执行奖励发放
          protected abstract Boolean awardRecord(String userId);
      }
      • 实现不同渠道的奖励业务
      @Slf4j
      @Service
      public class ToutiaoAwardStrategyService extends BaseAwardTemplate implements AwardStrategy {
          /**
           * 奖励发放接口
           */
          @Override
          public Boolean awardStrategy(String userId) {
              return super.awardTemplate(userId);
          }
      
          @Override
          public String getSource() {
              return "toutiao";
          }
      
          /**
           * 具体的业务奖励发放实现
           */
          @Override
          protected Boolean awardRecord(String userId) {
              log.info("头条渠道用户{}奖励50元红包!", userId);
              return Boolean.TRUE;
          }
      }
      
      @Slf4j
      @Service
      public class WeChatAwardStrategyService extends BaseAwardTemplate implements AwardStrategy {
          /**
           * 奖励发放接口
           */
          @Override
          public Boolean awardStrategy(String userId) {
              return super.awardTemplate(userId);
          }
      
          @Override
          public String getSource() {
              return "wx";
          }
      
          /***
           * 具体的业务奖励发放实现
           */
          @Override
          protected Boolean awardRecord(String userId) {
              log.info("微信渠道用户{}奖励100元红包!", userId);
              return Boolean.TRUE;
          }
      }
      • 定义工厂方法,对外统一暴露业务调用入口
      @Component
      public class AwardStrategyFactory implements ApplicationContextAware {
          private final static Map<String, AwardStrategy> MAP = new HashMap<>();
      
          @Override
          public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
              Map<String, AwardStrategy> beanTypeMap = applicationContext.getBeansOfType(AwardStrategy.class);
              beanTypeMap.values().forEach(strategyObj -> MAP.put(strategyObj.getSource(), strategyObj));
          }
      
          /**
           * 对外统一暴露的工厂方法
           */
          public Boolean getAwardResult(String userId, String source) {
              AwardStrategy strategy = MAP.get(source);
              if (Objects.isNull(strategy)) {
                  throw new RuntimeException("渠道异常!");
              }
              return strategy.awardStrategy(userId);
          }
      
          /**
           * 静态内部类创建单例工厂对象
           */
          private static class CreateFactorySingleton {
              private static AwardStrategyFactory factory = new AwardStrategyFactory();
          }
      
          public static AwardStrategyFactory getInstance() {
              return CreateFactorySingleton.factory;
          }
      }
      • 业务入口方法
      @RestController
      @RequestMapping("/activity")
      public class ActivityController {
       
          @PostMapping("/reward3")
          public void reward3(String userId, String source) {
              AwardStrategyFactory.getInstance().getAwardResult(userId, source);
          }
      }

      假如发起请求: POST http://localhost:8080/activity/reward3?userId=fei&source=wx

      2025-02-20 12:23:27.716  INFO 20769 --- [nio-8080-exec-1] c.a.c.e.o.c.p.s.BaseAwardTemplate        : fei 执行身份验证!
      2025-02-20 12:23:27.719  INFO 20769 --- [nio-8080-exec-1] c.a.c.e.o.c.p.s.BaseAwardTemplate        : fei 执行风控校验!
      2025-02-20 12:23:27.719  INFO 20769 --- [nio-8080-exec-1] a.c.e.o.c.p.s.WeChatAwardStrategyService : 微信渠道用户fei奖励100元红包!

      其他技巧

      • 使用三目运算符
      • 相同业务逻辑提取复用

      写在最后

      不论使用那种技巧,首先是我们在业务代码开发过程中一定要多思考,将复杂的业务逻辑能通过简洁的代码表现出来,这才是你的核心能力之一,而不是一个 curd boy。与君共勉,共同进步!

      Gitee 获取源码

      在线客服
      服务热线

      服务热线

      4008888355

      微信咨询
      二维码
      返回顶部
      ×二维码

      截屏,微信识别二维码

      打开微信

      微信号已复制,请打开微信添加咨询详情!