Java程序员必备奇淫巧技篇(下)

前言

前面我们分别讲解了Java编程的命名与注释、代码风格和编程技巧这些Java基础教程,今天我们继续讲解解Java程序员必备的技巧篇。

Java程序员必备奇淫巧技篇(下)

1. 函数设计要职责单一

我们在前面讲到单一职责原则的时候,针对的是类、模块这样的应用对象。实际上,对于函数的设计来说,更要满足单一职责原则。相对于类和模块,函数的粒度比较小,代码行数少,所以在应用单一职责原则的时候,没有像应用到类或者模块那样模棱两可,能多单一就多单一。

具体的代码示例如下所示:

public boolean checkUserIfExisting(String telephone, String username, String email)  {

  if (!StringUtils.isBlank(telephone)) {

​    User user = userRepo.selectUserByTelephone(telephone);

​    return user != null;

  }

  if (!StringUtils.isBlank(username)) {

​    User user = userRepo.selectUserByUsername(username);

​    return user != null;

  }

  if (!StringUtils.isBlank(email)) {

​    User user = userRepo.selectUserByEmail(email);

​    return user != null;

  }

  return false;

}

// 拆分成三个函数

public boolean checkUserIfExistingByTelephone(String telephone);

public boolean checkUserIfExistingByUsername(String username);

public boolean checkUserIfExistingByEmail(String email);

2. 移除过深的嵌套层次

代码嵌套层次过深往往是因为 if-else、switch-case、for 循环过度嵌套导致的。我个人建议,嵌套最好不超过两层,超过两层之后就要思考一下是否可以减少嵌套。过深的嵌套本身理解起来就比较费劲,除此之外,嵌套过深很容易因为代码多次缩进,导致嵌套内部的语句超过一行的长度而折成两行,影响代码的整洁。

解决嵌套过深的方法也比较成熟,有下面 4 种常见的思路。

去掉多余的 if 或 else 语句。代码示例如下所示:

// 示例一

public double caculateTotalAmount(List<Order> orders) {

  if (orders == null || orders.isEmpty()) {

​    return 0.0;

  } else { // 此处的 else 可以去掉

​    double amount = 0.0;

​    for (Order order : orders) {

​      if (order != null) {

​        amount += (order.getCount() * order.getPrice());

​      }

​    }

​    return amount;

  }

}

// 示例二

public List<String> matchStrings(List<String> strList,String substr) {

  List<String> matchedStrings = new ArrayList<>();

  if (strList != null && substr != null) {

​    for (String str : strList) {

​      if (str != null) { // 跟下面的 if 语句可以合并在一起

​        if (str.contains(substr)) {

​          matchedStrings.add(str);

​        }

​      }

​    }

  }

  return matchedStrings;

}

使用编程语言提供的 continue、break、return 关键字,提前退出嵌套。代码示例如下所示:

// 重构前的代码

public List<String> matchStrings(List<String> strList,String substr) {

  List<String> matchedStrings = new ArrayList<>();

  if (strList != null && substr != null){

​    for (String str : strList) {

​      if (str != null && str.contains(substr)) {

​        matchedStrings.add(str);

​        // 此处还有 10 行代码...

​      }

​    }

  }

  return matchedStrings;

}

// 重构后的代码:使用 continue 提前退出

public List<String> matchStrings(List<String> strList,String substr) {

  List<String> matchedStrings = new ArrayList<>();

  if (strList != null && substr != null){

​    for (String str : strList) {

​      if (str == null || !str.contains(substr)) {

​        continue;

​      }

​      matchedStrings.add(str);

​      // 此处还有 10 行代码...

​    }

  }

  return matchedStrings;

}

调整执行顺序来减少嵌套。具体的代码示例如下所示:

// 重构前的代码

public List<String> matchStrings(List<String> strList,String substr) {

  List<String> matchedStrings = new ArrayList<>();

  if (strList != null && substr != null) {

​    for (String str : strList) {

​      if (str != null) {

​        if (str.contains(substr)) {

​          matchedStrings.add(str);

​        }

​      }

​    }

  }

  return matchedStrings;

}

// 重构后的代码:先执行判空逻辑,再执行正常逻辑

public List<String> matchStrings(List<String> strList,String substr) {

  if (strList == null || substr == null) { // 先判空

​    return Collections.emptyList();

  }

  List<String> matchedStrings = new ArrayList<>();

  for (String str : strList) {

​    if (str != null) {

​      if (str.contains(substr)) {

​        matchedStrings.add(str);

​      }

​    }

  }

  return matchedStrings;

}

将部分嵌套逻辑封装成函数调用,以此来减少嵌套。具体的代码示例如下所示:

// 重构前的代码

public List<String> appendSalts(List<String> passwords) {

  if (passwords == null || passwords.isEmpty()) {

​    return Collections.emptyList();

  }

  List<String> passwordsWithSalt = new ArrayList<>();

  for (String password : passwords) {

​    if (password == null) {

​      continue;

​    }

​    if (password.length() < 8) {

​      // ...

​    } else {

​      // ...

​    }

  }

  return passwordsWithSalt;

}

// 重构后的代码:将部分逻辑抽成函数

public List<String> appendSalts(List<String> passwords) {

  if (passwords == null || passwords.isEmpty()) {

​    return Collections.emptyList();

  }

  List<String> passwordsWithSalt = new ArrayList<>();

  for (String password : passwords) {

​    if (password == null) {

​      continue;

​    }

​    passwordsWithSalt.add(appendSalt(password));

  }

  return passwordsWithSalt;

}

private String appendSalt(String password) {

  String passwordWithSalt = password;

  if (password.length() < 8) {

​    // ...

  } else {

​    // ...

  }

  return passwordWithSalt;

}

除此之外,常用的还有通过使用多态来替代 if-else、switch-case 条件判断的方法。这个思路涉及代码结构的改动,我们会在后面的章节中讲到,这里就暂时不展开说明了。

3. 学会使用解释性变量

常用的用解释性变量来提高代码的可读性的情况有下面 2 种。

常量取代魔法数字。示例代码如下所示:

public double CalculateCircularArea(double radius) {

  return (3.1415) * radius * radius;

}

// 常量替代魔法数字

public static final Double PI = 3.1415;

public double CalculateCircularArea(double radius) {

  return PI * radius * radius;

}

使用解释性变量来解释复杂表达式。示例代码如下所示:

if (date.after(SUMMER_START) && date.before(SUMMER_END)) {

  // ...

} else {

  // ...

}

// 引入解释性变量后逻辑更加清晰

boolean isSummer = date.after(SUMMER_START)&&date.before(SUMMER_END);

if (isSummer) {

  // ...

} else {

  // ...

}

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注

关注我们