编程规范大部分都简单明了,在代码细节方面,能立竿见影地改善代码质量。持续低层次、小规模重构依赖的基本上都是编码规范,这也是改善代码可读性的有效手段。
命名
命名对于代码的可读性来说非常重要,甚至可以说起决定性作用的。对于影响范围比较大的命名,比如包名、接口、类名,一定要反复斟酌、推敲。
-
命名多长最合适
在足够表达其含义的情况下,命名是越短越好。
对于一些默认的、大家都比较熟知的词(sec、str、num、doc)推荐用缩写。
对于作用域比较小的变量可以使用相对短的命名,例如函数内的临时变量;
对于类名这种作用域比较大的,推荐用更长的命名方式
命名的一个原则就是以能准确达意为目标。对于编码者自己来说,总感觉用什么样的命名都可以达意,但对不熟悉代码的同事来说就不这么认为了。所以命名的时候一定要学会换位思考,假设自己不熟悉这块代码,从代码阅读者的角度去考量命名是否足够直观。 -
利用上下文简化命名
public class User {
private String userName;
private String userPassword;
private String userAvatarUrl;
//...
}
public void uploadUserAvatarImageToAliyun(String userAvatarImageUri);
//利用上下文简化为:
public void uploadUserAvatarImageToAliyun(String imageUri);
-
命名要可读、可搜索
“可读”指不要用一些特别生僻、难发音的英文单词来命名,例如:plateaux、eyrie。可以用一些易读的词,例如:inkstone。
“可搜索”指用IDE编写代码时经常会用到“关键词联想”的方法来自动补全和搜索。因此在命名是最好能符合整个项目的命名习惯。比如:大家都用selectXXX,那就避免个人使用queryXXX;大家都用insertXXX,个人就不要使用addXXX -
如何命名接口和抽象类
接口命名通常两种比较常见:一种加前缀“i”,比如UserService implements IUserService
,另一种不加前缀,比如UserServiceImpl implements UserServiceImpl
抽象类通常也有两种,一种加前缀“Abstract”,另一种不加
对于接口和抽象类,选择那种命名方式都是可以的,只要项目里保持一致就行
注释
注释跟命名一样也很重要。很多人认为好的命名完全可以替代注释,如果需要注释,那说明命名不够好,这种观点有点太过极端。命名再好,毕竟有长度限制,不可能足够详尽,这时候注释就是一个很好的补充。
-
注释该写什么
注释的目的就是让代码更容易看懂。只要符合这个要求的内容,就可以写到注释里。注释的内容包括:做什么、为什么、怎么做。
/**
* (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 {
// ...
}
很多人认为“做什么、怎么做”可以在代码中体现出来,所以不要写,其实不然:
- 注释比代码承载的信息更多
对于类来说,包含的信息比较多,一个简单的命名不够全面详尽,这个时候在注释中写明“做什么”就合情合理- 注释起到总结性作用、文档的作用
在注释中,关于具体的代码实现思路,我们可以写一些总结性的说明、特殊情况的说明。这样能够让阅读代码的人通过注释就能大概了解代码的实现思路,阅读起来就会更加容易- 一些总结性注释能让代码结构更清晰
对于逻辑比较复杂的代码或者比较长的函数,如果不好提炼、不好拆分成小的函数调用,可以借助总结性的注释来让代码结构更清晰、更有条理
-
注释是不是越多越好
注释本身有一定的维护成本,所以并非越多越好。类和函数一定要写注释,而且要写得尽可能全面、详细,而函数内部的注释要相对少一些,一般都是靠好的命名、提炼函数、解释性变量、总结性注释来提高代码的可读性
代码风格
在一个团队、项目中保持风格统一,让代码像同一个人写出来的,整齐划一,这才是最好的风格。这样能减少阅读干扰,提高代码的可读性。
-
类、函数多大才合适
函数代码行数不好超过一个显示屏的垂直高度(大约50行左右),因为超过一屏之后,在阅读代码的时候,为了串联前后的代码逻辑,可能需要频繁的上下滚动屏幕,阅读体验不好,还容易出错。
对于类的代码行数的限制有个间接的判断标准:当一个类的代码读起来让你感觉头大;实现某个功能时不知道该用那个函数了;想用哪个函数翻半天找不到;只用一个小功能要引入整个类;此时就说明类的行数太多了。 -
一行代码多长最合适
Google Java Style Guide中,一行代码最长限制100字符。
遵循一个原则:一行代码最长不能超过IDE显示的宽度。需要滚动鼠标才能查看一行的全部代码,显然不利于代码的阅读。 -
善用空行分隔单元块
对于比较长的函数,为了让逻辑更加清晰,可以使用空行来分隔各个代码块。在类内部,成员变量与函数之间、静态成员变量与普通成员变量之间、函数之间,甚至成员变量之间,都可以通过添加空行的方式,让不同模块的代码之间的界限更加明确 -
四格缩进还是两格缩进
不管是用两格缩进还是四格缩进,一定不要用tab键缩进。整个团队保持一致即可。推荐两格缩进,节省空间 -
类中成员的排列顺序
类中先写成员变量后写函数。成员变量之间或函数之间,先写静态成员变量或函数,后写普通变量或函数
编程技巧
-
把代码分割成更小的单元块
大部分人阅读代码的习惯是先看整体再看细节。所以要有模块化和抽象思维,善于将大块的复杂逻辑提炼成类或函数,屏蔽掉细节,这样能极大地提高代码的可读性。 -
避免函数参数过多
函数包含的参数 >=5 时会影响到代码的可读性,使用起来也不方便。参数过多处理方法:考虑函数是否职责单一,能否通过拆分成多个函数的方式减少参数;将函数的参数封装成对象,如果函数是对外暴露的远程接口,将参数封装成对象还可以提高接口的兼容性。 -
勿用函数参数来控制逻辑
不要在函数中用布尔类型的标识参数来控制内部逻辑,true走A逻辑,false走B逻辑。这明显违背了单一职责原则和接口隔离原则。如果函数是private或者拆分后的两个函数经常同时被调用,可以酌情考虑保留标识参数。
根据参数是否为null来控制逻辑的也应该将其拆分成多个函数。 -
函数设计要职责单一
函数的设计也需要满足单一职责原则,函数的粒度比较小,代码行数少,所以在应用单一职责时能多单一就多单一 -
移除过深的嵌套层次
代码嵌套最好不超过两层,过深的嵌套本身理解就比较费劲,而且嵌套过深很容易因为代码多次缩进导致语句超过一行的长度,影响代码的整洁和阅读- 去掉多余的 if else语句
- 使用 continue、break、return提前退出嵌套
- 调整执行顺序来减少嵌套
- 将部分嵌套逻辑封装成函数调用,减少嵌套
public List matchStrings(List strList,String substr) {
List matchedStrings = new ArrayList<>();
if (strList != null && substr != null) {
for (String str : strList) {
// 跟下面的if语句可以合并在一起
if (str != null) {
if (str.contains(substr)) {
matchedStrings.add(str);
}
}
}
}
return matchedStrings;
}
- 学会使用解释性变量
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)) {
// ...
}
// 引入解释性变量后逻辑更加清晰
boolean isSummer = date.after(SUMMER_START)&&date.before(SUMMER_END);
if (isSummer) {
// ...
}
网友评论