如何减少代码中的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)
} }
优点 :适合复杂的业务逻辑,代码可扩展性强
缺点: 通常要配合工厂模式或者享元模式使用
如何减少代码中的if-else嵌套的更多相关文章
- 论减少代码中return语句的骚操作
一.写作背景 最近组内在推行checkstyle代码规范的检测,关于checkstyle的介绍可以参考:https://checkstyle.sourceforge.io, 在按照checkstyle ...
- FindBugs 入门——帮你减少代码中的bug数
FindBugs 入门 FindBugs 作用 开发人员在开发了一部分代码后,可以使用FindBugs进行代码缺陷的检查.提高代码的质量,同时也可以减少测试人员给你报的bug数. 代码缺陷分类 根据缺 ...
- 有效的减少代码中太多的if、else?-策略模式
写这篇文章的目的和上一篇单例模式一样,策略模式也是一种常用的设计模式,太多的if-else不仅看着不太美观而且不好维护,对于自己来说也等于复习了一遍策略模式.先说一下策略 模式的定义: 策略模式封装了 ...
- 如何在代码中减少if else语句的使用
前言 代码中嵌套的if/else结构往往导致代码不美观,也不易于理解.面向过程的开发中代码有大量的if else,在java中可以用一些设计模式替换掉这些逻辑,那么在js中是否也有类似的方法用来尽可能 ...
- 写代码的心得,怎么减少编程中的 bug?
遭遇 bug 的时候,理性的程序员会说:这个 bug 能复现吗? 自负型:这不可能,在我这是好好的. 经验型:不应该,以前怎么没问题? 幻想型:可能是数据有问题. 无辜型:我好几个星期都没碰这块代码了 ...
- Java基础学习总结(81)——如何尽可能的减少Java代码中bug
Java编程语言的人气自然无需质疑,从Web应用到Android应用,这款语言已经被广泛用于开发各类应用及代码中的复杂功能. 不过在编写代码时,bug永远是困扰每一位从业者的头号难题.在今天的文章中, ...
- php中嵌套html代码和html代码中嵌套php方式
php中嵌套html代码和html代码中嵌套php方式 一.总结 拷贝的话直接html代码是极好的方式 1.php中嵌套html代码(本质是原生php):a.原生嵌套<?php .....?&g ...
- 如何解决代码中if…else 过多的问题
前言 if...else 是所有高级编程语言都有的必备功能.但现实中的代码往往存在着过多的 if...else.虽然 if...else 是必须的,但滥用 if...else 会对代码的可读性.可维护 ...
- “System.OutOfMemoryException”类型的异常在 mscorlib.dll 中发生,但未在用户代码中进行处理
“System.OutOfMemoryException”类型的异常在 mscorlib.dll 中发生,但未在用户代码中进行处理 这个原因肯定不是因为程序内部的逻辑错误,或者别的什么情况. 想想,肯 ...
随机推荐
- golang-练习1
题目: 输入字符串,返回最大的单词. 实例:run#¥@!time 返回:time package main import ( "fmt" "strings" ...
- TLSv网络安全标准,会话加密协议展望未来
本文是关于TLSv1.3采用的三部分系列的第三部分也是最后一部分.它解决了网络加密和监控的选项,包括备用会话加密协议. 通过TLSv1.3的批准,并在IETF出版物队列中,是时候考虑部署选项和障碍,并 ...
- call_user_func_array — 调用回调函数,并把一个数组参数作为回调函数的参数
<?php function foobar($arg, $arg2) { echo __FUNCTION__, " got $arg and $arg2\n"; } clas ...
- 常用jstl
求list中某一值的和 <c:set var="total" value="${0}" /> <c:forEach var="tLi ...
- C#高级编程笔记(11至16章)异步/托管/反射/异常
11.1.2LINQ语句 LINQ查询表达式以from子句开始,以select或者group子句结束.在这两个子句之间可以跟零个或者多个from.let.where.join或者orderby子句. ...
- Shell输入命令时一些有用的快捷键
Ctrl + u: 从光标所在位置一直删除到开头 Ctrl + k: 从光标所在位置一直删除到尾 Ctrl + b: 光标向后移动一个字符 Ctrl + f: 光标后前移动一个字符 Alt + b: ...
- 【leetcode】1025. Divisor Game
题目如下: Alice and Bob take turns playing a game, with Alice starting first. Initially, there is a numb ...
- boost Shared Memory
Shared Memory Shared memory is typically the fastest form of interprocess communicatioin. It provide ...
- C++ 穷举算法 鸡兔同笼
#include "stdio.h" int qiongju(int head, int foot, int *chicken, int *rabbit) { int re, i, ...
- Vue的跨域设置
1.在使用vue开发的时候经常要涉及到跨域的问题,其实在vue cli中是有我们设置跨域请求的文件的. 2.当跨域无法请求的时候我们可以修改工程下config文件夹下的index.js中的dev:{} ...