一个快速迭代的项目,时间久了之后,代码中可能会充斥着大量的if/else,嵌套6、7层,一个函数几百行,简!直!看!死!人!

这个无限循环嵌套,只是总循环的一部分。。。我已经绕晕在黄桷湾立交

仔细数了数,一共有 11 层的嵌套!!!接手这种项目的同学,内心应该是绝望的。

出现这种情况的原因很多

  • 设计不够完善

  • 需求考虑不完全

  • 开发人员变动

但最为致命的是“懒”

你懒,我也懒,前期迭代懒得优化,来一个需求,加一个if,久而久之,就串成了一座金字塔。

当代码已经复杂到难以维护的程度之后,只能狠下心重构优化。那,有什么方案可以优雅的优化掉这些多余的if/else?

1. 提前return

这是判断条件取反的做法,代码在逻辑表达上会更清晰,看下面代码:

if (condition) {
// do something
} else {
return xxx;
}

其实,每次看到上面这种代码,我都心里抓痒,完全可以先判断 !condition,干掉else。

if (!condition) {
return xxx;
}
// do something

2. 策略模式

有这么一种场景,根据不同的参数走不同的逻辑,其实这种场景很常见。
最一般的实现:

if (strategy.equals("fast")) {
// 快速执行
} else if (strategy.equals("normal")) {
// 正常执行
} else if (strategy.equals("smooth")) {
// 平滑执行
} else if (strategy.equals("slow")) {
// 慢慢执行
}

看上面代码,有4种策略,有两种优化方案。

2.1 多态

interface Strategy {
void run() throws Exception;
}
class FastStrategy implements Strategy {
@Override
void run() throws Exception {
// 快速执行逻辑
}
}
class NormalStrategy implements Strategy {
@Override
void run() throws Exception {
// 正常执行逻辑
}
}
class SmoothStrategy implements Strategy {
@Override
void run() throws Exception {
// 平滑执行逻辑
}
}
class SlowStrategy implements Strategy {
@Override
void run() throws Exception {
// 慢速执行逻辑
}
}

具体策略对象存放在一个Map中,优化后的实现

Strategy strategy = map.get(param);
strategy.run();

上面这种优化方案有一个弊端,为了能够快速拿到对应的策略实现,需要map对象来保存策略,当添加一个新策略的时候,还需要手动添加到map中,容易被忽略。

2.2 枚举

发现很多同学不知道在枚举中可以定义方法,这里定义一个表示状态的枚举,另外可以实现一个run方法。

public enum Status {
NEW(0) {
@Override
void run() {
//do something
}
},
RUNNABLE(1) {
@Override
void run() {
//do something
}
};
public int statusCode;
abstract void run();
Status(int statusCode){
this.statusCode = statusCode;
}
}

重新定义策略枚举

public enum Strategy {
FAST {
@Override
void run() {
//do something
}
},
NORMAL {
@Override
void run() {
//do something
}
},
SMOOTH {
@Override
void run() {
//do something
}
},
SLOW {
@Override
void run() {
//do something
}
};
abstract void run();
}

通过枚举优化之后的代码如下

Strategy strategy = Strategy.valueOf(param);
strategy.run();

3. 学会使用 Optional

Optional主要用于非空判断,由于是jdk8新特性,所以使用的不是特别多,但是用起来真的爽。

使用之前:

if (user == null) {
//do action 1
} else {
//do action2
}

如果登录用户为空,执行action1,否则执行action 2,使用Optional优化之后,让非空校验更加优雅,间接的减少if操作

Optional<User> userOptional = Optional.ofNullable(user);
userOptional.map(action1).orElse(action2);

4. 数组小技巧

来自google解释,这是一种编程模式,叫做表驱动法,本质是从表里查询信息来代替逻辑语句,比如有这么一个场景,通过月份来获取当月的天数,仅作为案例演示,数据并不严谨。

一般的实现:

int getDays(int month){
if (month == 1) return 31;
if (month == 2) return 29;
if (month == 3) return 31;
if (month == 4) return 30;
if (month == 5) return 31;
if (month == 6) return 30;
if (month == 7) return 31;
if (month == 8) return 31;
if (month == 9) return 30;
if (month == 10) return 31;
if (month == 11) return 30;
if (month == 12) return 31;
}

优化后的代码

int monthDays[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int getDays(int month){
return monthDays[--month];
}

结束

if else作为每种编程语言都不可或缺的条件语句,在编程时会大量的用到。一般建议嵌套不要超过三层,如果一段代码存在过多的if else嵌套,代码的可读性就会急速下降,后期维护难度也大大提高。

如果你还有其它小技巧,欢迎留言!!!

下方查看历史文章

从CMS到G1:LinkedIn个人主页调优实战

函数式编程让你忘记设计模式

vavr:让你像写Scala一样写Java

再谈源码阅读

本号专注于后端技术、JVM问题排查和优化、Java面试题、个人成长和自我管理等主题,为读者提供一线开发者的工作和成长经验,期待你能在这里有所收获。

面试官:优化代码中大量的if/else,你有什么方案?的更多相关文章

  1. 面试官:Redis中字符串的内部实现方式是什么?

    在面试间里等候时,感觉这可真暖和呀,我那冰冷的出租屋还得盖两层被子才能睡着.正要把外套脱下来,我突然听到了门外的脚步声,随即门被打开,穿着干净满脸清秀的青年走了进来,一股男士香水的淡香扑面而来. 面试 ...

  2. 面试官:Redis中哈希数据类型的内部实现方式是什么?

    面试官:Redis中基本的数据类型有哪些? 我:Redis的基本数据类型有:字符串(string).哈希(hash).列表(list).集合(set).有序集合(zset). 面试官:哈希数据类型的内 ...

  3. 面试官:Redis中集合数据类型的内部实现方式是什么?

    虽然已经是阳春三月,但骑着共享单车骑了这么远,还有有点冷的.我搓了搓的被冻的麻木的手,对着前台的小姐姐说:"您好,我是来面试的."小姐姐问:"您好,您叫什么名字?&quo ...

  4. 面试官:Redis中有序集合的内部实现方式是什么?

    面试官:Redis中基本的数据类型有哪些? 我:Redis的基本数据类型有:字符串(string).哈希(hash).列表(list).集合(set).有序集合(zset). 面试官:有序集合的内部实 ...

  5. 【性能优化】面试官:Java中的对象都是在堆上分配的吗?

    写在前面 从开始学习Java的时候,我们就接触了这样一种观点:Java中的对象是在堆上创建的,对象的引用是放在栈里的,那这个观点就真的是正确的吗?如果是正确的,那么,面试官为啥会问:"Jav ...

  6. 【高并发】面试官:Java中提供了synchronized,为什么还要提供Lock呢?

    写在前面 在Java中提供了synchronized关键字来保证只有一个线程能够访问同步代码块.既然已经提供了synchronized关键字,那为何在Java的SDK包中,还会提供Lock接口呢?这是 ...

  7. 面试官:Java中对象都存放在堆中吗?你知道逃逸分析?

    面试官:Java虚拟机的内存分为哪几个区域? 我(微笑着):程序计数器.虚拟机栈.本地方法栈.堆.方法区 面试官:对象一般存放在哪个区域? 我:堆. 面试官:对象都存放在堆中吗? 我:是的. 面试官: ...

  8. DSO 优化代码中的 Schur Complement

    接上一篇博客<直接法光度误差导数推导>,DSO 代码中 CoarseInitializer::trackFrame 目的是优化两帧(ref frame 和 new frame)之间的相对状 ...

  9. 如何优化代码中大量的if/else,switch/case?

    前言 随着项目的迭代,代码中存在的分支判断可能会越来越多,当里面涉及到的逻辑比较复杂或者分支数量实在是多的难以维护的时候,我们就要考虑下,有办法能让这些代码变得更优雅吗? 正文 使用枚举 这里我们简单 ...

随机推荐

  1. docker 中,修改了 mysql 配置,如何重启 mysql?

    直接重新启动容器: docker restart containerID/containerName

  2. Spring Boot 配置文件application.properties

    #########COMMON SPRING BOOT PROPERTIES ######========CORE PROPERTIES=========== #SPRING CONFIG (Conf ...

  3. chrom代理插件

    1.SwitchyOmega 2.Resource Override

  4. 批处理教程之cls、pause命令

    cls 命令     清除屏幕.执行该命令后,屏幕上的所有信息都被清除,光标重新定位至屏幕左上角. REM 和 :: REM为注释命令,一般用来给程序加上注解,该命令后的内容不被执行,但能回显. 其次 ...

  5. 微信小程序音频背景播放

    由于微信小程序官方将音频的样式固定死了,往往再工作中和UI设计师设计出来的样式不符,故一般都采用背景音频播放来实现自定义的UI样式的音频播放,即使用官网API提供的BackgroundAudioMan ...

  6. 数据结构——链队列(linked queue)

    /* linkedQueue.c */ /* 链队列 */ #include <stdio.h> #include <stdlib.h> #include <stdboo ...

  7. 《Three js开发指南》 PDF

    电子版仅供预览及学习交流使用,下载后请24小时内删除,支持正版,喜欢的请购买正版书籍:<Three js开发指南> pdf下载地址:链接: https://pan.baidu.com/s/ ...

  8. [LeetCode] 767. Reorganize String 重构字符串

    Given a string S, check if the letters can be rearranged so that two characters that are adjacent to ...

  9. TextView实现文字水平滚动效果

    有时候我们使用TextView显示文本,只想把所有内容用一行显示出来,但是一行又显示不完,就需要让文本实现水平滚动的效果. 具体实现方法如下: 1,实现自定义TextView并实现isFocused( ...

  10. 外文投稿时应该如何填写有关Social Media的问题?

    外文投稿时应该如何填写有关Social Media的问题? 1 *Please supply our social media editor with a "tweet" or s ...