前言
在日常的开发中,可能会由于迭代时间紧等原因,不会过多的去考虑代码质量,遇到逻辑,直接if-else。本文主要来谈谈优化代码中的if-else的一些方法。
提前return
优化前:
if(condition){ //doSomething }else{ return ; }
刚开始实习的时候,就一直用上面的这种写法,还会给每个条件加上注释。一旦doSomething中的代码变多,整个代码可读性就会变差,也不优雅。后来在师父的指导下,改成了下面这种。
优化后:
if(!condition){ return ; } //doSomething
使用三目运算符
优化前:
int price ; if(condition){ price = 80; }else{ price = 100; }
优化后:
int price = condition?80:100;
使用枚举
优化前:
String OrderStatusDes; if(orderStatus==0){ OrderStatusDes ="订单未支付"; }else if(OrderStatus==1){ OrderStatusDes ="订单已支付"; }else if(OrderStatus==2){ OrderStatusDes ="已发货"; }
优化后:
// 先定义一个枚举 @Getter public enum OrderStatusEnum { UN_PAID(0,"订单未支付"),PAIDED(1,"订单已支付"),SENDED(2,"已发货"); private int code; private String desc; OrderStatusEnum(int code, String desc){ this.code = code; this.desc = desc; } OrderStatusEnum getByCode(int orderStatus) { for (OrderStatusEnum temp : OrderStatusEnum.values()) { if (temp.getCode() == orderStatus) { return temp; } } return null; } }
// 然后上面的一堆if else就可以优化成一行代码 String OrderStatusDes = OrderStatusEnum.getByCode(orderStatus).getDesc();
上面这个逻辑比较简单,如果逻辑比较多,还可以在枚举类中定义方法,不过目前在我所接触的项目中还没有遇到。例如:
// 定义一个枚举类 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; } }
Status status = Status .valueOf(param); status.run();
使用 Optional
Optional是Java8的新特性。有时候if-else比较多,是因为非空判断导致的,这个时候就可以派上用场了。
优化前
String str = "jay@huaxiao"; if (str != null) { System.out.println(str); } else { System.out.println("Null"); }
优化后:
Optional<String> strOptional = Optional.of("jay@huaxiao"); strOptional.ifPresentOrElse(System.out::println, () -> System.out.println("Null"));
关于Optional的一些API和进一步学习,推荐阅读这篇文章:还在重复写空指针检查代码?考虑使用 Optional 吧!
表驱动法
这是一种编程模式,是一种使你可以在表中查找信息,而不必用很多的逻辑语句(if或Case)来把它们找出来的方法。举个例子。
优化前:
if (param.equals(value1)) { doAction1(someParams); } else if (param.equals(value2)) { doAction2(someParams); } else if (param.equals(value3)) { doAction3(someParams); } // ...
下面的优化,会把map抽象成表,在map中查找信息,而省去不必要的逻辑语句。
优化后:
Map<?, Function<?> action> actionMappings = new HashMap<>(); // 这里泛型 ? 是为方便演示,实际可替换为你需要的类型 // 初始化 @PostConstruct public void init(){ actionMappings.put(value1, (someParams) -> { doAction1(someParams)}); actionMappings.put(value2, (someParams) -> { doAction2(someParams)}); actionMappings.put(value3, (someParams) -> { doAction3(someParams)}); } // 省略多余逻辑语句 actionMappings.get(param).apply(someParams);
而其中的doAction,还可以进一步抽象出一个service服务,专门放其中的逻辑。
策略模式+工厂方法
优化前:
String medalType = "guest"; if ("guest".equals(medalType)) { System.out.println("展示嘉宾勋章"); } else if ("vip".equals(medalType)) { System.out.println("展示会员勋章"); } else if ("guard".equals(medalType)) { System.out.println("展示守护勋章"); }
优化后:
首先,进行抽象,把每个逻辑代码块,抽象成一个公共的接口。示例中是展示勋章,可以写出如下的代码:
//勋章接口 public interface IMedalService { void showMedal(); }
然后,根据不同的条件,定义对应的策略实现类:
//守护勋章策略实现类 public class GuardMedalServiceImpl implements IMedalService { @Override public void showMedal() { System.out.println("展示守护勋章"); } } //嘉宾勋章策略实现类 public class GuestMedalServiceImpl implements IMedalService { @Override public void showMedal() { System.out.println("展示嘉宾勋章"); } } //VIP勋章策略实现类 public class VipMedalServiceImpl implements IMedalService { @Override public void showMedal() { System.out.println("展示会员勋章"); } }
最后,再定义工厂类,用于管理实现的这些策略类:
//勋章服务工产类 public class MedalServicesFactory { private static final Map<String, IMedalService> map = new HashMap<>(); static { map.put("guard", new GuardMedalServiceImpl()); map.put("vip", new VipMedalServiceImpl()); map.put("guest", new GuestMedalServiceImpl()); } public static IMedalService getMedalService(String medalType) { return map.get(medalType); } }
使用:
String medalType = "guest"; IMedalService medalService = MedalServicesFactory.getMedalService(medalType); medalService.showMedal();
上面这种优化方案有一个弊端,当添加一个新策略的时候,还需要手动添加到工厂类的map中,容易被忽略。
总结
对if-else进行适当的优化,能够是代码变得优雅,同时还可以降低耦合性,利于后期的扩展等。但也有缺点,增加了代码的阅读门槛,不够直观,特别是业务非常复杂的情况下,没法清晰的展示各个类、接口之间的关系。我很想知道在我们公司的项目中,有没有实操的逻辑,但就我目前参与的项目,实在是没有看到,可能还是因为业务不够复杂吧。不过,项目中已经出现了类似屎山的情况,一个列表接口,有很多种查询条件,代码中用了非常多的if-else,同时一些逻辑也侵入到了XML中的SQL,如果后续会进行优化的话,我再补充。