收藏!简单且优雅的8种干掉if else的方法(非设计模式方法)

2 年前,我在 b 站上录制了一个视频,如何优雅的干掉 if else。我当时提出了“断言”+“短路”的形式,最直接的干掉 if else。很多人非常受益,今天我再整理成文字分享给大家!

if else 是我们写代码时,使用频率最高的关键词之一,然而有时过多的 if else 会让我们感到脑壳疼,例如下面这个伪代码:

if else 多层嵌套
if else 多层嵌套
超复杂的if else
超复杂的if else

是不是很奔溃?想象你现在是一个新手程序员,或者是一个刚入职的小司机,这样的代码,你敢维护吗?

基于此,我在这里推荐几种消除 if else 的方法,希望能够帮助到大家!

多使用“断路”return

if("".equals(author)){
  // ...
  System.out.println("你好");
}else if("大佬".equals(author)){
  // ...
  System.out.println("你好");
} else {
  throw new Exception("error");
}

上面这么代码,我们这样这样修改:

if("".equals(author)){
  // ...
  System.out.println("你好");
  return;
}

if("大佬".equals(author)){
  // ...
  System.out.println("你好");
  return;
} 

throw new Exception("error");

当然,我这个案例嵌套的层次太少,部分人感觉不明显。下面我们一起看一个稍微复杂一点的案例。

public String getTweetTitle(int type) {
    String result;
    if (type == 0) {
        throw new IllegalArgumentException("参数有误");
    }

    //长贴-->获得长帖标题
    if (isPaperTweet(type)) {
        result = getPaperTweetTitle();
    } else {
        // 视频贴-->获得视频贴标题
        if (isVideoTweet(type)) {
            result = getVideoTitle();
        } else {
            result = getDefaultTitle();
        }
    }
    return result;
}

我们使用“断路”的方法,可以改成如下方式:

public String getTweetTitle(int type) {
    // 条件检查
    if (type == 0) {
        throw new IllegalArgumentException("参数有误");
    }

    // 长贴-->获得长帖标题
    if (isPaperTweet(type)) {
        return getPaperTweetTitle();
    }

    // 视频贴-->获得视频贴标题
    if (isVideoTweet(type)) {
        return getVideoTitle();
    }

    return getDefaultTitle();
}

上面的代码是不是看起来更清爽一些!实际上,阿里巴巴开发手册中也推荐我这种做法了!

《阿里巴巴开发手册》中,关于多 if-else的使用推荐
《阿里巴巴开发手册》中,关于多 if-else的使用推荐

减少无用的 if else

我们继续接着看一个例子:

if(100 == age){
  return true;
} else {
  return false;
}

这是我工作多年来,见到不少同事这样写的(不是故意黑他们)。

我们可以这样改:

return 100 == age;

直接返回判断的结果。

使用三元运算

实际上,从效率上来讲,三元运算的效率也比 if else 高!

if(age > 18){
  result = "成年人可以打游戏超过1个小时";
} else {
  result = "未成年人打游戏不能超过1个小时";
}

改成三元运算:

result = age > 18 ? "成年人可以打游戏超过1个小时" : "未成年人打游戏不能超过1个小时";

多使用断言

继续看下面这个例子:

if(null == name || "".equals(name)){
  throw new Exception("姓名不能为空");
}

if(age < 18){
  throw new Exception("年龄不能小于18");
}

我们可以改成下面的实现:

Assert.hasLength(name, "姓名不能为空");
Assert.isTrue(age < 18, "年龄不能小于18");

或者是你自己封装一个参数校验方法。

public abstract class PreCheck {
    public PreCheck() {
    }

    public static void preCheckNotNull(Object obj) {
        if (obj == null) {
            throw new ServerException("attr data cannot be empty");
        }
    }

    public static void preCheckNotNull(Object obj, String msg) {
        if (obj == null) {
            throw new ServerException(msg);
        }
    }

    public static void preCheckNotNull(Object obj, ErrorMessage errorMessage) {
        if (obj == null) {
            throw new ServerException(errorMessage);
        }
    }

    public static void preCheckArgument(boolean checked, String msg) {
        if (checked) {
            throw new ServerException(msg);
        }
    }

    public static void preCheckArgument(boolean checked, ErrorMessage errorMessage) {
        if (checked) {
            throw new ServerException(errorMessage);
        }
    }

    public static BigDecimal preCheckBigDecimal(String val, String msg) {
        try {
            return new BigDecimal(val);
        } catch (Exception var3) {
            throw new ServerException(msg);
        }
    }

    public static BigDecimal preCheckBigDecimal(String val, ErrorMessage errorMessage) {
        try {
            return new BigDecimal(val);
        } catch (Exception var3) {
            throw new ServerException(errorMessage);
        }
    }
    
    // ...
}

上面这个是我常用的一个工具类。

使用 map 取代 if else

if (t == 1) {
    type = "百度";
} else if (t == 2) {
    type = "字节";
} else if (t == 3) {
    type = "阿里";
} else if (t == 4) {
    type = "腾讯";
}
// ...

如果 if 太多,就显得太长了。我见过一个 if else if 超过 300 行的代码。这个时候三元运算符也不太好用了,这里我推荐使用 map 来做。

Map<Integer, String> typeMap = new HashMap<>();
typeMap.put(1, "百度");
typeMap.put(2, "字节");
typeMap.put(3, "阿里");
typeMap.put(4, "腾讯");
// ...

return typeMap.get(type);

减少没必要的 if

一些代码我们要合理的抽取,提出公共的部分。下面我们再看一个例子:

String result = "";
if(age == 1){
  // todo 
  result = "年龄太小了";
}

if(age == 2){
  // todo 
  result = "年龄太小了";
}

// ...

上面的代码我们可以将两个 if 进行合并。

String result = "";
if(age == 1 || age == 2){
  // todo 
  result = "年龄太小了";
}
// ...

当然,如果是一个范围,也可以进行范围判断。

String result = "";
if(age > 0 || age < 12){
  // todo 
  result = "年龄太小了";
}
// ...

反向逻辑减少 if else

多数情况下,我们写代码都是正向逻辑。下面我通过一些反向逻辑减少一些 if else。

// 方法 A
List<DocFieldDto> list = dto.getDocFieldDtoList();
if (!CollectionUtils.isEmpty(list)) {
    // todo ...
}

// 方法 B
if(a != null){
  // todo
  if(b != null){
    // todo
  }
}

我们可以利用反向逻辑进行代码精简改造!

// 方法 A
List<DocFieldDto> list = dto.getDocFieldDtoList();
if(CollectionUtils.isEmpty(list)){
  return;
}

// 方法 B
if(null == a){
  return;
}

// todo
if(b == null){
  return;
}
// todo

多使用 Optional

Optional 还是很好用的,我个人非常喜欢用。继续看下面这个例子:

String str = "java和前端都难";
if (str == null) {
    System.out.println("null");
} else {
    System.out.println(str);
}

我们可以这样改:

String str2 = "java和前端都难";
String result = Optional.ofNullable(str2).orElse("null");
System.out.println(result);

//输出:java和前端都难

//等同于:
if (str2 != null) {
    System.out.println(str2);
} else {
    System.out.println("null");
}

再比如,我们通常有一个对象,需要一层一层的去判断取值。

String isocode = user.getAddress().getCountry().getIsocode().toUpperCase();

// 或者有些程序员加上了判断
if (user != null) {
    Address address = user.getAddress();
    if (address != null) {
        Country country = address.getCountry();
        if (country != null) {
            String isocode = country.getIsocode();
            if (isocode != null) {
                isocode = isocode.toUpperCase();
            }
        }
    }
}

如果用 Optional,看起来就更舒服了。

@Test
public void whenChaining_thenOk() {
    User user = new User("anna@gmail.com", "1234");

    String result = Optional.ofNullable(user)
      .flatMap(u -> u.getAddress())
      .flatMap(a -> a.getCountry())
      .map(c -> c.getIsocode())
      .orElse("default");

    assertEquals(result, "default");
}

也可以通过方法引用进一步缩减:

String result = Optional.ofNullable(user)
  .flatMap(User::getAddress)
  .flatMap(Address::getCountry)
  .map(Country::getIsocode)
  .orElse("default");

当然,Optional 在某些场景下是不能够完全代替 if else 的,这点视情况自行判断。

以上就是我们经常使用的缩减 if else 的小妙招。不喜轻喷!

除此之外,很多人可能还看到过各种设计模式干掉 if else 的,我就不多说了。包括:多态、反射、枚举、策略模式等不在本文的讨论范围内。

收藏!简单且优雅的8种干掉if else的方法(非设计模式方法)

: » 收藏!简单且优雅的8种干掉if else的方法(非设计模式方法)

原创文章,作者:wure,如若转载,请注明出处:https://blog.ytso.com/251415.html

(0)
上一篇 2022年5月2日
下一篇 2022年5月2日

相关推荐

发表回复

登录后才能评论