如何减少代码中的if-else嵌套
实际项目中,往往有大量的if-else语句进行各种逻辑校验,参数校验等等,大量的if-else,语句使代码变得臃肿且不好维护,本篇文章结合我自己的经验,就减少if-else语句给出以下几种方案,分别适用于不同的场景,供大家参考,如有疑问或者建议,请大家及时指出;
一. 方案一:使用三元表达式:
//使用if-else语句 String str; if (user.getAge()>18){ str="已成年"; }else { str="未成年"; } //使用三元表达式 str=user.getAge()>18?"成年":"未成年";
二. 方案二:使用JDK1.8中的Optional类包装
//使用 if 语句 User user=userService.findById(userId); if (null==user){ throw new RuntimeException("参数错误,未找到指定用户"); } //使用Optional类包装 Optional.ofNullable(userService.findById(userId)).orElseThrow(()->new RuntimeException("参数错误,未找到指定用户"));
使用Optional类的好处还在于在包装成Optional容器后,可以使用函数式编程中的相关方法,例如filter(),map()方法,等等,用于筛选和转换我们业务中的逻辑和对象,使得代码得灵活性大大提高,例如:
//筛选出大于18岁的用户,如果没有就抛出异常 Optional.ofNullable(userService.findById(userId)) .filter(x->x.getAge()>18) .orElseThrow(()->new RuntimeException("参数错误,未找到指定用户"));
代码是否简洁了很多呢
优点: 可以进行较为复杂的逻辑判断
缺点: 条件判断不宜过多,过多的条件判断下不宜使用该方式
三.方案三:使用断言Assert类
在Spring的org.springframework.util包中,内置了Assert断言类,用于条件表达式的判断
//使用断言类 User user=userService.findById(userId); Assert.notNull(user, "参数错误,未找到指定用户");
断言类中的方法返回值是void,断言类常用于我们做Junit单元测试,由于单元测试的方法均是无参数,无返回值的方法,因此Assert断言类用于测试程序的返回值是否符合我们预期是再好不过了
优点:内置了很多判断方法,例如 notNull,notEmpty,equal等方法,代码可读性强,相对方案一和方案二,可以适用于较多的判断分支;
缺点:在断言失败时,异常只能是IllegalArgumentException(message),适用于较简单的逻辑判断
四.方案四:使用@Validate注解进行入参校验的判断
在企业开发中,进行表单验证,以及接口的入参校验时,往往会使用大量的if-else语句做参数校验,这样代码会显得特别臃肿和冗余,因此我们可以使用封装好的库来进行校验,在JSR-303规范中,定义了参数校验的注解@Valid,个大框架厂商例如spring,基于JSR303规范,提供了各自的实现,并且提供了很多高级的功能,例如@Validated就是@Valid的变体;
以下摘自org.springframework.validation.annotation中@Validated注解的文档注释
Variant of JSR-303's {@link javax.validation.Valid}, supporting the specification of validation groups. Designed for convenient use with Spring's JSR-303 support but not JSR-303 specific.
//接口定义 @RequestMapping("/update") public void updateUser(@RequestBody @Validated User user) { userService.updateUser(user); } //参数校验 public class User implements Serializable { @NotNull(message = "参数不能为空") private Integer id; @NotBlank(message = "参数不能为空") private String username; @NotBlank(message = "参数不能为空") private String password; @NotEmpty(message = "参数不能为空") private List<String> desc; //这里可以通过正则来校验时间格式是否正确 @NotNull(message = "参数不能为空") @Pattern(regexp = "xxxx",message ="时间格式不符合规范" ) private Date date; }
注意:如果@Validated参数校验失败,会抛出异常,如果需要在代码中接收异常,可以在接口的参数中,添加参数BindingResult,添加了这个类,之后,异常就会被封装到这个类中,不会向外抛出,我们可以调用这个类的API去获取具体的异常信息,之后,我们可以根据异常信息,去定制化我们自己的响应
public ModelAndView save(@Validated CategoryForm form, BindingResult bindingResult, Map<String, Object> map) { if (bindingResult.hasErrors()) { map.put("msg", bindingResult.getFieldError().getDefaultMessage()); map.put("url", "/sell/seller/category/index"); return new ModelAndView("common/error", map); } }
优点: 非常适合在特定环境下做接口入参的校验
缺点: 局限性大,无法在业务逻辑中使用
五.方案五:策略模式
策略模式是设计模式之一,设计模式的初衷是为了解决代码中的特定问题而存在,百度一下策略模式的定义:
在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。
简单来说就是,算法(策略)和对象已经预先定义好,随传入参数的改变而选择不同的算法(策略),更加具体的语义不就是根据不用的条件(if--else),选择性的执行不同的代码吗? 本人在开发中也是屡次使用策略模式来重构复杂的if-else逻辑判断,屡试不爽,大大提高代码的优雅性;
下面是在企业开发中本人的例子,在Spring中如何使用策略模式 使用场景: 需求:多个接口,响应相同,根据参数传入的类型,使用不同的策略;
//策略上下文 @Configuration public class StrategyContext{ @Resource public Map<String,Strategy> strategyMap; public List<Resp> doGet(String type){ Strategy strategy =strategyMap.get(type); retun strategy.doStrategy(); } } //配置策略 @Configuration public class StrategyConfig{ @Resource public ServiceImpl1 serviceImpl1 @Resource public ServiceImpl2 serviceImpl2 @Bean public Map<String,Strategy> getMap(){ Map<String,Strategy> strategyMap =new HashMap() strategyMap.put("1",new ServiceImpl1()); strategyMap.put("2",new ServiceImpl2()); return strategyMap } //策略接口类 public interface Strategy{ List<Resp> doStrategy(); } //具体策略1 public class ServiceImpl1 implements Strategy{ //重写策略方法 @Override publicList<Resp> doStrategy(){ ... } } //具体策略2 public class ServiceImpl2 implements Strategy{ //重写策略方法 @Override publicList<Resp> doStrategy(){ ... } } //在Controller层的代码中注入策略上下文 public class AAAController{ @Autowired public StrategyContext context; public List<Resp> getXXX(String type){ //设计模式-策略模式 return context.doGet(type) } }
优点 :适合复杂的业务逻辑,代码可扩展性强
缺点: 通常要配合工厂模式或者享元模式使用
相关文章
- 08 | 递归:如何用三行代码找到“最终推荐人”?
- 转载:如何在面试中写出好的代码
- 转载:如何避免代码中的if嵌套
- 漂亮代码
- [探讨]如何成为有代码洁癖的程序员?
- Sql Server中一个表2个字段关联同一个表(代码解决)
- python基础编程:python如何实现浪漫的烟花秀(附代码)
- 百度攻城狮训练营2021-工程能力study2 -- 2.1 代码的艺术 脑图整理
- 如何打破35岁测试/开发程序员的魔咒?生命中不仅只有代码......
- 如何有效的解决代码的圈复杂度
- Idea Live Templates代码模板
- 强化学习代码实战-03动态规划算法(冰壶游戏测试)
- SAP MM MB5L事务代码'仅总计'选项初探
- mac上将代码上传到github以及github对100M以上文件限制上传的处理(lfs)。
- 如何用Eclipse调试(debug)Java代码?
- SwiftUI内功之Xcode中如何使用代码段重用代码
- 一个系列带你搞定前端面试的手写代码环节(5) --- 数组去重
- 关于pytorch在pycharm中部分代码提示失效的解决方法
- 巧用HashMap一行代码统计单词出现次数
- 浅析Vue3 CompositionAPI如何替换Vue Mixins:mixin的缺点(命名冲突、隐式依赖)、CompositionAPI如何解决这些缺陷(代码提取、代码重用)
- 浅析Java Lambda表达式、如何理解Lambda、如何使用Lambda简化代码(结合stream处理遍历、配合Optional优雅的处理null情况)
- 华为OD机试 - 高效的任务规划(JavaScript) | 机试题+算法思路+考点+代码解析 【2023】
- 华为OD机试 -二叉树层次遍历(JavaScript) | 机试题+算法思路+考点+代码解析 【2023】
- 华为OD机试 - 猴子爬山(Python)| 真题+思路+考点+代码+岗位
- Verilog 代码规范
- WPS Office for Linux项目中止 计划开源Linux代码
- 如何用 120 行代码,实现交互完整的拖拽上传组件?
- 向PE文件植入后门代码技术讨论