java中if条件中删除此行代码_Java最新面试题精讲系列02之如何去除代码中过多的if语句...

Java最新面试题精讲系列02之如何去除代码中过多的if语句

一. 面试题目

优化代码中大量的if/else语句,你有什么解决方案?

二. 考察意图

我们在平时开发写的代码中,if-else判断语句基本是必不可少的。当我们的判断语句只有一两层的时候还好,但是过度地、不必要地使用 if...else语句,会对代码的可读性、可扩展性造成负面影响,另外如果判断语句越来越多,后期进行项目维护也会比较困难,对于后面接手项目的人来说,差不多就是一个很头疼的问题了。

所以去除掉代码中过多的if...else语句的能力高低,反映的是程序员对软件重构、设计模式、面向对象设计、架构模式、数据结构等多方面技术的综合运用能力。所以我们的代码中要合理使用 if...else,不能没有设计,也不能过度设计。这些对技术的综合、合理地运用都需要程序员在工作中不断的摸索总结。

这也是该面试题的考察目的!

三. 问题表现

if (condition1) {

doSomeThing1();

} else if (condition2) {

doSomeThing2();

} else if (condition3) {

doSomeThing3();

} else if (condition4) {

doSomeThing4();

} else {

doSomeThing5();

}...

四. 问题原因

出现这种情况的原因很多,比如​设计不够完善;

需求考虑不完善;

开发人员变动等。

基本上就是前期迭代懒得优化,来一个需求,加一个if,再来一个需求,再加一个if。久而久之,就成了一座if...else的金字塔。

五. 解决方案

那么我们如何解决代码中过多的if...else语句呢?可以考虑采用以下解决方案。适时的return;

策略模式:多态、函数式编程、枚举;

表驱动模式;

职责链模式;

注解驱动;

事件驱动;

有限状态机;

Optional;

Assert;

1. 适时的return

比如我们有以下的代码:

if (condition) {

// do something} else {

return xxx;

}

我们先判断!condition,将return语句放在前面,这样就可以去掉else语句了,相对于上面的语句代码清晰了不少。

其实上面的代码完全可以按如下方式优化:

if (!condition) {

return xxx;

}

// do something

我们先判断!condition,将return语句放在前面,这样就可以去掉else语句了,相对于上面的语句代码清晰了不少

2. 策略模式

比如有这么一个开发场景,我们要根据不同的性别执行不同的操作,类似的这种场景是很常见的。 通常的实现如下:

if ("man".equals(strategy)) {

// 执行男人相关操作} else if ("woman".equals(strategy)) {

// 执行女人相关操作} else if ("other".equals(strategy)) {

// 执行其他操作}

对于以上的代码,我们可以采用以下策略进行优化。

2.1 多态的策略优化模式

首先定义一个接口类Strategy。

public interface Strategy {

void run() throws Exception;

}

然后写若干个实现类:

//男人的策略实现类@Slf4j

public class ManStrategy implements Strategy {

@Override

public void run() throws Exception {

// 快速男人的逻辑 log.debug("执行男人相关的逻辑...");

}

}

//女人的策略实现类@Slf4j

public class WomanStrategy implements Strategy {

@Override

public void run() throws Exception {

// 快速女人的逻辑 log.debug("执行女人相关的逻辑...");

}

}

//其他人的策略实现类@Slf4j

public class OtherStrategy implements Strategy {

@Override

public void run() throws Exception {

// 快速其他的逻辑 log.debug("执行其他相关的逻辑...");

}

}

具体使用简单示例:

public class StrategyTest {

public static void main(String[] args) {

try {

Strategy strategy = initMap("man");

strategy.run();

} catch (Exception e) {

e.printStackTrace();

}

}

private static Strategy initMap(String key) {

//使用简单示例 HashMap map = new HashMap<>();

map.put("man", new ManStrategy());

map.put("woman", new WomanStrategy());

map.put("other", new OtherStrategy());

return map.get(key);

}

}

该方案的缺点:

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

2.2 函数式编程的策略优化模式

我们可以对上面的代码进行稍作修改,采用java8里的函数式编程方法来简化代码。

首先定义一个interface接口。

public interface Strategy {

void run() throws Exception;

}

然后使用函数式编程进行代码的操作。

@Slf4j

public class StrategyTest {

public static void main(String[] args) {

//使用简单示例 HashMap map = new HashMap<>();

map.put("man", () -> log.debug("执行男人相关的逻辑..."));

map.put("woman", () -> log.debug("执行女人相关的逻辑..."));

map.put("other", () -> log.debug("执行其他人相关的逻辑..."));

try {

map.get("woman").run();

} catch (Exception e) {

e.printStackTrace();

}

}

}

2.3 枚举的策略优化模式

定义一个枚举策略类。

@Slf4j

public enum Strategy {

//男人状态 MAN(0) {

@Override

void run() {

//执行男人相关操作 log.debug("执行男人相关的逻辑");

}

},

//女人状态 WOMAN(1) {

@Override

void run() {

//执行女人相关操作 log.debug("执行女人相关的逻辑");

}

},

//其他状态 OTHER(2) {

@Override

void run() {

//执行其他相关操作 log.debug("执行其他相关的逻辑");

}

};

abstract void run();

public int statusCode;

Strategy(int statusCode) {

this.statusCode = statusCode;

}

}

简单使用示例:public static void main(String[] args) {

try {

//简单使用示例

String param = String.valueOf(Strategy.WOMAN);

Strategy strategy = Strategy.valueOf(param);

strategy.run();

} catch (Exception e) {

e.printStackTrace();

}

}

3. 表驱动模式

对于逻辑表达模式固定的 if...else 代码,可以通过某种映射关系,将逻辑表达式用表格的方式表示,也就是从表里查询信息,来找到某个输入所对应的处理逻辑函数,使用这个处理函数进行运算。适用于逻辑表达模式固定的 if...else语句。

例如下面的代码:

if (param.equals(value1)) {

doAction1(someParams);

}else if (param.equals(value2)) {

doAction2(someParams);

}else if (param.equals(value3)) {

doAction3(someParams);

}

可以利用Java 8 的 Lambda 和 Functional Interface来进行重构。

// 这里泛型 ? 是为方便演示,实际可替换为你需要的类型Map, Function> action> actionMappings = new HashMap<>();

// When initactionMappings.put(value1, (someParams) -> { doAction1(someParams)});

actionMappings.put(value2, (someParams) -> { doAction2(someParams)});

actionMappings.put(value3, (someParams) -> { doAction3(someParams)});

// 省略 null 判断actionMappings.get(param).apply(someParams);

4. 职责链模式

当 if...else 中的条件表达式灵活多变,无法将条件中的数据抽象为表格并用统一的方式进行判断时,这时应将对条件的判断权交给每个功能组件。并用链的形式将这些组件串联起来,形成完整的功能。适用于条件表达式灵活多变,没有统一的形式。

职责链的模式在开源框架的 Filter、Interceptor 功能的实现中可以见到很多。下面看一下通用的使用模式:

public void handle(request) {

if (handlerA.canHandle(request)) {

handlerA.handleRequest(request);

} else if (handlerB.canHandle(request)) {

handlerB.handleRequest(request);

} else if (handlerC.canHandle(request)) {

handlerC.handleRequest(request);

}

}

重构代码:

public void handle(request) {

handlerA.handleRequest(request);

}

public abstract class Handler {

protected Handler next;

public abstract void handleRequest(Request request);

public void setNext(Handler next) { this.next = next; }

}

public class HandlerA extends Handler {

public void handleRequest(Request request) {

if (canHandle(request)) doHandle(request);

else if (next != null) next.handleRequest(request);

}

}

5. 注解驱动

通过 Java 注解(或其它语言的类似机制)定义执行某个方法的条件。在程序执行时,通过对比入参与注解中定义的条件是否匹配,再决定是否调用此方法。具体实现时,可以采用表驱动或职责链的方式实现。适用于条件分支很多,对程序扩展性和易用性均有较高要求的场景。通常是某个系统中经常遇到新需求的核心功能。

6. 事件驱动

通过关联不同的事件类型和对应的处理机制,来实现复杂的逻辑,同时达到解耦的目的。从理论角度讲,事件驱动可以看做是表驱动的一种,但从实践角度讲,事件驱动和前面提到的表驱动有多处不同。具体来说:表驱动通常是一对一的关系;事件驱动通常是一对多;

表驱动中,触发和执行通常是强依赖;事件驱动中,触发和执行是弱依赖

正是上述两者不同,导致了两者适用场景的不同。具体来说,事件驱动可用于如订单支付完成触发库存、物流、积分等功能。

7. 有限状态机

有限状态机通常被称为状态机(无限状态机这个概念可以忽略)。先引用维基百科上的定义:有限状态机(英语:finite-state machine,缩写:FSM),简称状态机,是表示有限个状态以及在这些状态**之间的转移和动作等行为的数学模型。

其实,状态机也可以看做是表驱动的一种,其实就是当前状态和事件两者组合与处理函数的一种对应关系。当然,处理成功之后还会有一个状态转移处理。

虽然现在互联网后端服务都在强调无状态,但这并不意味着不能使用状态机这种设计。其实,在很多场景中,如协议栈、订单处理等功能中,状态机有这其天然的优势。因为这些场景中天然存在着状态和状态的流转。

8. Optional

Java 代码中的一部分 if...else 是由非空检查导致的。因此,降低这部分带来的 if...else 也就能降低整体的 if...else 的个数。

Java 从 8 开始引入了 Optional 类,用于表示可能为空的对象。这个类提供了很多方法,用于相关的操作,可以用于消除 if...else。开源框架 Guava 和 Scala 语言也提供了类似的功能。适用于有较多用于非空判断的 if...else。

示例代码:

String str = "Hello World!";

if (str != null) {

System.out.println(str);

} else {

System.out.println("Null");

}

利用Optional优化之后:

Optional optional = Optional.of("Hello World!");

optional.ifPresentOrElse(System.out::println, () -> System.out.println("Null"));

9. Assert 模式

上一个方法适用于解决非空检查场景所导致的 if...else,类似的场景还有各种参数验证,比如还有字符串不为空等等。很多框架类库,例如 Spring、Apache Commons 都提供了工具里,用于实现这种通用的功能。这样大家就不必自行编写 if...else 了。适用于通常用于各种参数校验。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值