这里作为(II)的第二个续篇,继续复杂的嵌套if else 的处理。 为了保持篇幅不会太长,以一篇新的文章形式给出。
化简复杂的if else语句,基本的手段
- 针对头重脚轻的if else,使用return快速返回,从而减少嵌套层数。
- 合并分支。有些分支的执行内容相同,往往意味着可以合并为一个分支
- 扁平化。
这里给出最后一个举例,也是从网上随便搜索摘录的
原始代码
List<TWorkFlowwork> wfwList=errorProcessingService.findWorkFlowworkByWorkType("7",workbillcode.getId()+""); boolean flag=false; if(wfwList!=null&&wfwList.size()>0){ for(int i=0;i<wfwList.size();i++){ TWorkFlowwork wfw=wfwList.get(i); if(wfw!=null){//当前待办是原件校验并且如果已经结束了则激活原件校验待办 if(wfw.getStatus()!=null&&!"".equals(wfw.getStatus())){ if("1".equals(wfw.getStatus())){ flag=true; break; } } } } if(!flag){//如果原件校验待办都结束了,则产生一条原件校验待办 TWorkBillcode wb=errorProcessingService.findWorkBillcodeByParameters(flow.getBussid(),flow.getBusstype()); wb.setIsmatchpage("1"); errorProcessingService.updateWorkBillcode(wb); } }
老规矩,简单点评一下这个代码:唉~~~~~~~
- 魔幻数字"7",“1”
- 大量的空对象判断。 这个不是表示严谨,而是代码设计有问题
- 极深的if else 嵌套,主要都是极端的头重脚轻形式的if 语句
首先,if(wfwList!=null&&wfwList.size()>0){ 超级的头重脚轻,采用return 直接返回
其次,for(int i=0;i<wfwList.size();i++){ TWorkFlowwork wfw=wfwList.get(i); 可以利用java的语法甜头,或者说是惯用法,替换为for (TWorkFlowwork wfw : wfwList)
然后,if (wfw!=null) 又可以用卫语句处理,不过这里不能使用return直接返回,而是应该用continue
最后,后面if status的判断实际都可以合并起来
if(wfw.getStatus()!=null&&!"".equals(wfw.getStatus()) && "1".equals(wfw.getStatus())){ flag=true; break; }
仔细分析,不难发现wfw.getStatus()!=null&&!"".equals(wfw.getStatus()) 根本是多余的。
于是代码变成这个样子
List<TWorkFlowwork> wfwList=errorProcessingService.findWorkFlowworkByWorkType("7",workbillcode.getId()+""); boolean flag=false; if(wfwList==null || wfwList.size()==0) { return; } for (TWorkFlowwork wfw : wfwList) { //当前待办是原件校验并且如果已经结束了则激活原件校验待办 if (wfw == null) { continue; } if("1".equals(wfw.getStatus())){ flag=true; break; } } if(!flag){//如果原件校验待办都结束了,则产生一条原件校验待办 TWorkBillcode wb=errorProcessingService.findWorkBillcoHideByParameters(flow.getBussid(),flow.getBusstype()); wb.setIsmatchpage("1"); errorProcessingService.updateWorkBillcode(wb); }
接下来,本来想对第一个循环做一个方法抽取,因为实际操作比较像查询——查询是否所有原件已经校验结束。改成查询之后,不仅含义上清楚到无需注释,而且可以去掉讨厌的标记变量flag以及wfwList为空的判断。
可惜没有全部代码,不知道这样修改是否会产品副作用。因为对最后一段“如果原件校验待办都结束了,则产生一条原件校验待办”这个注释无法拿捏得很准,这个“产生一条”是指产生下一条?
所以说,理想的情况是让代码自注释。如果写了注释,一定要维护代码的同时维护注释,错误的注释比没有注释更糟糕。不管如何,原本复杂的if else 我们已经大大简化了。
最后再啰嗦一下,面试时代码的编写确实是必不可少的一部分:从这份代码就可以看出
- 原作者对java的基本语法不熟;// 循环语句很拙劣,可能是从C转入没多久
- 之前系统的培训过或者认真看过相关编码的书; // 大量的魔幻数字,wfwList.size()==0 而不是isEmpty()
- 代码量不大。// 这个代码片段不长,却非常费解。而且代码层次感不强,各种高层的接口和底层的接口杂糅在一起
最后的最后,做个简单的总结。
这一部分主要是举例讨论复杂的锯齿形 if else语句的处理。基本方法不外乎三个
- 针对头重脚轻的if else,使用return快速返回,从而减少嵌套层数。
- 合并分支。有些分支的执行内容相同,往往意味着可以合并为一个分支
- 扁平化。
里面的举例,一般我是尽可能按照重构,一步步的列出。
- 修改if else 最忌惮的是天马行空,自负自己对代码的理解,直接重新改写条件语句。但另一方面,相信各位看官也注意到了,理解又是必不可少的,完全死死的做逻辑变形是异常繁琐的(这个在第二个例子中尤为明显),具体如何操作,不好意思,这就是"修改代码的艺术"。口才不行,修行还靠个人。
- 不要做不成熟的优化。相对来说,代码的清晰度高于性能的优化,而且很多时候两者并不是冲突的,当代码更清新了,往往有更好的优化方案。
- 举例中的一些代码风格,比如return快速返回,不是每个人都能接受。求同存异,这也是个人座右铭。
- 大千世界,简化 if else的方法肯定不止上面几种。但这几种还是很实用,欢迎个人崇拜,不要怀疑者,不要脑残粉。(玩笑,勿当真,只是想说,"不要怕,不要悔",刚开始时,尽管做,不要太多怀疑)
最后,如果对重构还有兴趣,可以看一看《重构--我的遗留系统改进之路》,这是一个培训ppt,写得不错。这里推荐一下