public class User {
private String name;
private String password;
private String avatarUrl;
//...
}
User user = new User();
user.getName(); // 借助user对象这个上下文
除了类之外,函数参数也可以借助函数这个上下文来简化命名。关于这一点,我举了下面这个例子,你一看就能明白,我就不多啰嗦了。
public void uploadUserAvatarImageToAliyun(String userAvatarImageUri);
//利用上下文简化为:
public void uploadUserAvatarImageToAliyun(String imageUri);
// 错误案例
Long a = 10000L;
userService.getById(a);
// 正确案例
Long userId = 10000L;
userService.getById(userId);
// 错误案例
package com.cloud.customerCompany;
public class customerCompanyService {
public void Get() {
Long Id = 123L;
super.get(Id);
}
}
// 正确案例
package com.cloud.customer.company;
public class CustomerCompanyService {
public void get() {
Long id = 123L;
super.get(id);
}
}
http url中的单个单词不得定义过长,不使用驼峰形式。举例:/queryByName → /query/name(或/query-by-name)。
抽象类命名使用Abstract或Base开头;异常类命名使用Exception结尾;测试类命名以它要测试的类的名称开始,以Test结尾。
常量、枚举成员名全部大写,单词间用下划线(_)隔开,力求语义表达完整清楚。
// 错误案例
public static final String defaultName = "张三";
public enum CompanyType {Normal, Sub_Company};
// 正确案例
public static final String DEFAULT_NAME = "张三";
public enum CompanyType {NORMAL, SUB_COMPANY};
// 错误案例
User user = new User();
boolean isSuccess = user.getIsSuccess();
// 正确案例
User user = new User();
boolean success = user.getSuccess();
命名很重要,注释跟命名同等重要。很多书籍认为,好的命名完全可以替代注释。如果需要注释,那说明命名不够好,需要在命名上下功夫,而不是添加注释。实际上,这样的观点有点太过极端。命名再好,毕竟有长度限制,不可能足够详尽,而这个时候,注释就是一个很好的补充。
注释的目的就是让代码更容易看懂。只要符合这个要求的内容,你就可以将它写到注释里。总结一下,注释的内容主要包含这样三个方面:做什么、为什么、怎么做。我来举一个例子给你具体解释一下。
/**
* (what) Bean factory to create beans.
*
* (why) The class likes Spring IOC framework, but is more lightweight.
* * (how) Create objects from different sources sequentially:
* user specified object > SPI > configuration > default object.
*/
public class BeansFactory {
// ...
}
public boolean isValidPasword(String password) {
// check if password is null or empty
if (StringUtils.isBlank(password)) {
return false;
}
// check if the length of password is between 4 and 64
int length = password.length();
if (length < 4 || length > 64) {
return false;
}
// check if password contains only a~z,0~9,dot
for (int i = 0; i < length; ++i) {
char c = password.charAt(i);
if (!((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '.')) {
return false;
}
}
return true;
}
左大括号是否要另起一行呢?这个也有争论。PHP 程序员喜欢另起一行,Java 程序员喜欢跟上一条语句放到一起。具体代码示例如下所示:
// PHP
class ClassName
{
public function foo()
{
// method body
}
}
// Java
public class ClassName {
public void foo() {
// method body
}
}
// 重构前的代码
public void invest(long userId, long financialProductId) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.DATE, (calendar.get(Calendar.DATE) + 1));
if (calendar.get(Calendar.DAY_OF_MONTH) == 1) {
return;
}
//...
}
// 重构后的代码:提炼函数之后逻辑更加清晰
public void invest(long userId, long financialProductId) {
if (isLastDayOfMonth(new Date())) {
return;
}
//...
}
public boolean isLastDayOfMonth(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.DATE, (calendar.get(Calendar.DATE) + 1));
if (calendar.get(Calendar.DAY_OF_MONTH) == 1) {
return true;
}
return false;
}
public User getUser(String username, String telephone, String email);
// 拆分成多个函数
public User getUserByUsername(String username);
public User getUserByTelephone(String telephone);
public User getUserByEmail(String email);
②将函数的参数封装成对象。示例代码如下所示:
public void postBlog(String title, String summary, String keywords, String content, String category, long authorId);
// 将参数封装成对象
public class Blog {
private String title;
private String summary;
private String keywords;
private Strint content;
private String category;
private long authorId;
}
//修改后
public void postBlog(Blog blog);
//简化前
long downloadRetry1 = 1000L * 60; // 下载第一次回调间隔
long downloadRetry2 = 1000L * 60; // 下载第二次回调间隔
long downloadRetry3 = 1000L * 60; // 下载第三次回调间隔
long downloadRetry4 = 1000L * 60; // 下载第四次回调间隔
DownloadMessage message = new DownloadMessage(Apply.getId(), downloadRetry1, downloadRetry2, downloadRetry3,downloadRetry4);
//简化后
int delayTime = 4;
DownloadMessage message = new DownloadMessage(Apply.getId(), delay, delayTime);
public void buyCourse(long userId, long courseId, boolean isVip);
// 将其拆分成两个函数
public void buyCourse(long userId, long courseId);
public void buyCourseForVip(long userId, long courseId);
// 拆分成两个函数的调用方式
boolean isVip = false;
//...省略其他逻辑...
if (isVip) {
buyCourseForVip(userId, courseId);
} else {
buyCourse(userId, courseId);
}
// 保留标识参数的调用方式更加简洁
boolean isVip = false;
//...省略其他逻辑...
buyCourse(userId, courseId, isVip);
public List<Transaction> selectTransactions(Long userId, Date startDate, Date endDate) {
if (startDate != null && endDate != null) {
// 查询两个时间区间的transactions
}
if (startDate != null && endDate == null) {
// 查询startDate之后的所有transactions
}
if (startDate == null && endDate != null) {
// 查询endDate之前的所有transactions
}
if (startDate == null && endDate == null) {
// 查询所有的transactions
}
}
// 拆分成多个public函数,更加清晰、易用
public List<Transaction> selectTransactionsBetween(Long userId, Date startDate, Date endDate) {
return selectTransactions(userId, startDate, endDate);
}
public List<Transaction> selectTransactionsStartWith(Long userId, Date startDate) {
return selectTransactions(userId, startDate, null);
}
public List<Transaction> selectTransactionsEndWith(Long userId, Date endDate) {
return selectTransactions(userId, null, endDate);
}
public List<Transaction> selectAllTransactions(Long userId) {
return selectTransactions(userId, null, null);
}
private List<Transaction> selectTransactions(Long userId, Date startDate, Date endDate) {
// ...
}
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);
①去掉多余的 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;
}
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 {
// ...
}
四、参考链接
https://www.jianshu.com/nb/50853864