在平时的实践生产中,伴随着业务逻辑越来越复杂,if-else
的滥用的越来越厉害。当然其并不影响代码的逻辑使用,至于其可读性那只能是仁者见仁智者见智。就我个人而言,我是很反感在代码中使用if的判空和逻辑判断。除非是业务紧急或者实在是想不出好的办法才会使用if-else
, 毕竟无脑使用是绝对没问题的。
本文代码地链接
1. 编码规范
编码规范能够简化if-else
的使用,是基于JDK所提供的基本能力实现的,同是能够很好避免满屏的if-else
1.1 三目运算符
public GenderEnum getGender(int genderValue){
if(genderValue == GenderEnum.FEMALE.getValue()){
return GenderEnum.FEMALE;
}else {
return GenderEnum.MALE;
}
}
======================================== After Change =============================
public GenderEnum getGenderAfterChange(int genderValue){
return genderValue == GenderEnum.FEMALE.getValue()? GenderEnum.FEMALE:GenderEnum.MALE;
}
虽然三目运算符是一个很基本的逻辑判断方式,但是在公司中使用的人太少了,基本上上来就是if-else
。有时候要是能看到代码中有三目运算符都会眼前一亮,得看看git提交记录是哪位写的。另外三目运算符还可以解决Lambda中的final定义字段的问题。如下:
public void test(){
int genderValue = 0;
GenderEnum genderEnum = null;
if(genderValue == GenderEnum.FEMALE.getValue()){
genderEnum = GenderEnum.FEMALE;
}else {
genderEnum = GenderEnum.MALE;
}
/******************************************************************************************************************/
final GenderEnum genderEnumFinal = genderValue == GenderEnum.FEMALE.getValue() ? GenderEnum.FEMALE: GenderEnum.MALE;
}
在上述的代码中,变量genderEnum是不可以用于lambda中,而genderEnumFinal是可以用于lambda表达式的,所以很好的解决了不可变的问题。
1.2 Optional的应用
Optional是JDK8推出的新用法,虽然整个类的代码很少,但是很大程度上解决了判空的问题。
没有Optional的情况:
if( null != person && null != person.getTeacher()){
return person.getTeacher().getName();
}else{
return "";
}
==========================================================================
Optional的使用
return Optional.ofNullable(person)
.map(Person::getTeacher)
.map(Teacher::getName)
.orElse("");
1.3自定义lambda表达式
//1.定义一个函数式接口
@FunctionalInterface
public interface BooleanFunction<T> {
T handleCondition(Supplier<? super T> ifFunction, Supplier<? super T> elseFunction);
}
//2.写一个Boolean工具类进行判断
public class BooleanUtil<T> {
//支持多个boolean结果, 相当于 或 条件
public static BooleanFunction isAnyMatch(Boolean... booleans) {
boolean result = Arrays.stream(booleans).filter(Objects::nonNull).anyMatch(Boolean::booleanValue);
return getBooleanFunction(result);
}
//支持多个boolean结果, 相当于 与 条件
public static BooleanFunction isAllMatch(Boolean... booleans){
boolean result = Arrays.stream(booleans).filter(Objects::nonNull).allMatch(Boolean::booleanValue);
return getBooleanFunction(result);
}
//支持多个boolean的lambda表达式结果, 相当于 与 条件
public static BooleanFunction isAllMatch(BooleanSupplier... booleanSuppliers){
boolean result = Arrays.stream(booleanSuppliers).filter(Objects::nonNull).map(BooleanSupplier::getAsBoolean).allMatch(Boolean::booleanValue);
return getBooleanFunction(result);
}
//支持多个boolean的lambda表达式结果, 相当于 或 条件
public static BooleanFunction isAnyMatch(BooleanSupplier... booleanSuppliers) {
boolean result = Arrays.stream(booleanSuppliers).filter(Objects::nonNull).map(BooleanSupplier::getAsBoolean).anyMatch(Boolean::booleanValue);
return getBooleanFunction(result);
}
private static BooleanFunction getBooleanFunction(boolean result){
return (ifFunction, elseFunction) -> result ? ifFunction.get() : Optional.ofNullable(elseFunction).map(Supplier::get).orElse(null);
}
public static void main(String[] args) {
String result = (String)BooleanUtil.isAnyMatch( () -> StringUtils.equals("hh","hhe")).handleCondition(
() -> "if function",
null
);
System.out.println(result); //null
String result1 = (String)BooleanUtil.isAnyMatch(StringUtils.equals("hh","hhe")).handleCondition(
() -> "if function",
() -> "else function"
);
System.out.println(result1); //else function
}
}
自定义的函数接口让if-else
的逻辑像写文章一样连贯,当然这种观点也是仁者见仁智者见智,喜欢写if-else
的守旧派绝对会认为这就是换汤不换药的改变,十分鸡肋。所以这种优化方式看个人,最主要还得看leader。如果你用了别人看不习惯,认为维护很麻烦当然认为你的方式是有问题的。甚至一些保守的公司连lambda的都不允许使用,如果你所在的公司是这样的话,我还是劝你尽早离职,毕竟公司会影响你个人发展的前景。因为你以后提出一些新颖的想法绝对会被守旧的模式所否定,如果一次又一次的被否定后会让你的大脑停滞思考一些新颖的方法。
2.逻辑拆分
2.1拆分方法
Person person = new Person();
if(null == id) {
person.setId("");
person.setDomainName("empty");
}else {
person.setId(id);
person.setDomainName(id + "domainName");
}
return person;
==========================================================================================================
Person person = new Person();
person.setId(id);
person.setDomainName(id + "domainName");
if(null == id){
person.setId("");
person.setDomainName("empty");
}
return person;
上述是将else中的逻辑抽了出来,先做了一个塞值操作,后置的if判断逻辑如果需要执行会对之前的赋值进行覆盖。在生产实践中,需要自行判断if 和else中需要执行的频次,通常情况下,id为null的很少会被执行的,所以此处将else中的逻辑放上去;如果id为null执行频次很高,就要求把if中的逻辑提取出来,然后之前的else逻辑变成if即可。
2.2 else逻辑提前return
if (null != id) {
Person person = testService.getById(id);
if (null != person) {
return person.getId();
}
return null;
} else {
return null;
}
===============================================================================================================
if(null == id){
return null;
}
Person person = testService.getById(id);
if(null == person){
return null;
}
return person.getId();
将不需要执行的数据进行提前return,减少if-else逻辑,让代码看起来更加清爽,逻辑清晰。
3.设计模式
//根据角色类型做出相应的操作
public void doActionByRole(String role){
if(role.equals(RoleEnum.HEADMASTER_ROLE)){
System.out.println("校长审作业");
}else if(role.equals(RoleEnum.TEACHER_ROLE)){
System.out.println("老师改作业");
}else if(role.equals(RoleEnum.STUDENT_ROLE)){
System.out.println("学生写作业");
}else {
System.out.println("");
}
}
3.1工厂模式
//使用工厂模式实现
//1.定义顶层接口
public interface Role {
void doAction();
}
//2.每一个角色实现接口
public class HeadermasterRole implements Role{
@Override
public void doAction() {
System.out.println("校长审作业");
}
}
public class StudentRole implements Role {
@Override
public void doAction() {
System.out.println("学生写作业");
}
}
public class TeacherRole implements Role {
@Override
public void doAction() {
System.out.println("老师改作业");
}
}
//3.提供工厂方法,根据role返回对应的role对象
public class RoleFactory {
private static final Map<String, Role> ROLE_MAP = ImmutableMap.<String, Role>builder()
.put(RoleEnum.TEACHER_ROLE.getValue(), new TeacherRole())
.put(RoleEnum.STUDENT_ROLE.getValue(), new StudentRole())
.put(RoleEnum.HEADMASTER_ROLE.getValue(), new HeadermasterRole())
.build();
public static Role getRole(String name) {
return ROLE_MAP.getOrDefault(name, null);
}
}
//4.运行demo
public class Demo {
public static void main(String[] args) {
//工厂模式实现
RoleFactory.getRole("student").doAction();
}
}
工厂模式对开闭原则十分友好,如果以后需要增加一些新的角色,只需要实现一些新的接口,代码中的逻辑不会发生改变。
开闭原则:对扩展开放,对修改关闭3.2策略模式(不能解决)
//1.提供策略的类, 根据不同的策略对象执行对应方法
public class RoleStrategy {
private final Role role;
public RoleStrategy(Role role) {
this.role = role;
}
public void doActionByRole() {
role.doAction();
}
}
//2.运行demo
public class Demo {
public static void main(String[] args) {
//策略模式实现
if(role.equals(RoleEnum.HEADMASTER_ROLE.getValue())){
new RoleStrategy(new HeadermasterRole());
}else if(role.equals(RoleEnum.TEACHER_ROLE.getValue()){
new RoleStrategy(new TeacherRole())
}else if(role.equals(RoleEnum.STUDENT_ROLE.getValue())){
new RoleStrategy(new StudentRole())
}
}
}
单纯的策略模式实际上就只有以上内容,实际上是不能解决if-else的逻辑;而工厂模式之所以能解决关键是含有Role对象的Map,根据roleName可以映射到相应的对象进而实现消除if-else的效果。
3.3 枚举类+策略
//定义枚举类型
public enum NameEnum {
ZHANG_SAN("张三") {
public void doAction() {
System.out.println("我是张三");
}
}, LI_SI("李四") {
@Override
public void doAction() {
System.out.println("我是李四");
}
}, WANG_WU("王五") {
@Override
public void doAction() {
System.out.println("我是王五");
}
}, ZHAO_QI("赵七") {
@Override
public void doAction() {
System.out.println("我是赵七");
}
}, TIAN_BA("田八") {
@Override
public void doAction() {
System.out.println("我是田八");
}
};
//声明一个Map
private static final Map<String, NameEnum> NAME_ENUM_MAP = Collections.unmodifiableMap(ImmutableMap.<String, NameEnum>builder()
.put(ZHANG_SAN.getValue(), ZHANG_SAN)
.put(LI_SI.getValue(), LI_SI)
.put(WANG_WU.getValue(), WANG_WU)
.put(ZHAO_QI.getValue(), ZHAO_QI)
.put(TIAN_BA.getValue(), TIAN_BA)
.build());
private final String name;
NameEnum(String name) {
this.name = name;
}
public String getValue() {
return this.name;
}
//定义策略方法
public abstract void doAction();
public static void main(String[] args) {
NAME_ENUM_MAP.get("田八").doAction(); // 输出: 我是田八
}
}
实际上述你也可以重新定义一个接口,然后枚举类实现该接口,这样枚举类中的每一个枚举都要实现接口中的策略方法,也能达到相同的效果。由于我觉得重新定义一个接口很没必要,所以在枚举类中定义了一个抽象方法,实际上达到的效果是一样的。其实主要结果if-else的关键还是构建的枚举Map,通过map拿到对应的枚举然后执行对应的策略。
4.总结
实际开发中,我们应该尽量避免多重if-else的嵌套使用,当然我们不要强行的消除if-else,一定要保持理性,需要消除才去消除。其实if-else的滥用我总结有以下两点:1.开发迭代周期过快,开发人员来不及思考;2.开发人员不想思考;3.前人写了很多if-else,后人继续堆屎山。