主要参考了阿里巴巴开发规范,特此说明
一、通用规范
1、注释
总体原则是: 对外接口必须写;内部接口不建议使用 ,如果名字已经可以解释其意义,则不需要加注释,如果不能解释则可以加
1)属性注释
/** xxx **/
private
String name;
public
void
setName(String name){
//xxx
do
();
}
2、文件结构
1)类的成员顺序:public > private > final > static > 实例成员;类结构:成员 > 构造方法 > 静态方法 > 实例方法
说明:通常使用者会更关注public 属性/方法
public
class
User{
public
final
static
String key1=
'key1'
;
public
static
String key2=
"key2"
;
public
String key3=
"key3"
;
private
String key4=
"key4"
;
public
User(){
}
public
static
void
setKey3(String key3){
}
public
void
setKey4(String key4){
}
private
void
foo(){
}
}
2)列限制:200,尽量在一行显示完整,超出需要换行,换行时遵循如下原则:
a 第二行相对第一行缩进 4 个空格,从第三行开始,不再继续缩进,参考示例。
b 运算符与下文一起换行。
c 方法调用的点符号与下文一起换行。
sb.append(
"zi"
).append(
"xin"
)...
.append(
"huang"
)...
.append(
"huang"
)...
.append(
"huang"
);
d 在多个参数超长,逗号后进行换行。
e 在括号前不要换行,如下反例
method(args1, args2, args3, ...
,argsX);
public
static
String name;
private
int
id;
public
void
method1(){
}
public
void
method2(){
}
3、命名规范
不能使用拼音进行命名,统一使用准确的英文进行命名
不采用简写方式命名(除公认的常用简写,或公司/小组字典表有描述)。命名过长比不能理解更好
1)、包名
2)、接口与类的命名
接口不要以 I 开头。如:IUserService,而直接采用具体的命名方式如UserService
3)、抽象类命名
抽象类命名使用:Abstract+名词的方式进行命名,如:AbstractMessage
4)、实现类命名
a 基于 SOA 的理念,暴露出来的服务一定是接口,内部的实现类用 Impl 的后缀与接口区别。例如UserServiceImpl
b 对于只有一个实现类的情况(外部接口除外),通常先不采用接口方式,直接采用实现类即可
c 如果有多个实现类,则采用名称+抽象名称+Impl,如UserMessageImpl、AdminMessageImpl
5)、变量命名
a 所有变量(描述状态的除外)统一以准确的名词性英文命名,名词性英文语法如下:
- 普通名词,如:user、clubMember、order等
- 组合名词,即名词+名词,如:clubMemberServiceOrder,paymentResult等
- 带修饰语(定语)名词,如:checkingResult,messageSendingTask(主动,用ing),closedOrder(已经关闭的订单,用ed)
b 描述状态的变量统一以准确的形容词性英文命名,形容词性英文语法如下:
- 普通形容词,如:active,inactive,valid,invalid等
- 动词转形容词,表示状态,如:close > closed,stop > stopped等
- 动词转形容词,标示能动,如:delete > deletable,use > useful等
c 对于反映状态的变量,不要在命名前面加“is”,因为自动生成的get方法,对于boolean值,方面名自动会变为is***
常量用全大写,单词之间用“_”分割,如:
public
static
final
String QUERYCLUBMEMBER_HQL=”…”;
d 对于成员变量,其名称可省略所属类的名称,如:
public
class
User {
private
String userName;
//NOT GOOD
private
String name;
//GOOD
}
- 方法名命名规则:
- 动词:init,validate,pay等
- 动词+介词+(宾语):compareTo,getById等
- 动宾短语(表示动作):createUser,publishPrivilege
- 谓表短语(表示状态):isClosed,isUserExisted,canUserBeDeleted等
-
接口类中的方法和属性不要加任何修饰符号 (public 也不要加 ,保持代码的简洁性)
- 单复数的使用,对于一些动作需要操作多个对象,方法名要通过名词复数反映出来,例如:deleteOrders(删除订单,可能多个)
- 如果一个方法设计两个动作或对象,用“And”连接,如:createProductAndTag,但一般情况下,不推荐一个方法做多于一件事情
- 不要使用简写,除非是公司级别或者业界已经通用的约定或字典表定义表示 ,比如I18n,则可以使用。因为简写很难阅读,容易误解,宁愿方法名稍微长一些,也要让方法名用正确的短语来表述,由于一个方法一般不建议做多于一件事情,所以方法名一般不会太长
- 一些Java业界约定俗成的方法命名:
- 与…进行比较:compareTo
- 获取单例对象:getInstance
- 是否相等:equals
- 初始化:init
- 对于dao层,其名称可省略所属类的名称,如:
public
interface
UserDao {
int
createUser(User user);
//NOT GOOD
int
create(User user);
//GOOD
}
接口、类的命名约定
类名
|
命名
|
示例
|
---|---|---|
Controller类 | **Controller | OrderController |
DAO层 | **Dao | UserDao |
Entity(领域对象) | 实体名 | User |
Interceptor类 | **Interceptor | AuthenticationInterceptor |
Servlet Filter类 | **Filter | ApplicationContextFilter |
Servlet类 | **Servlet | SystemInitServlet |
VO/DTO(视图对象) | 实体名+VO | UserVO |
工具类命名 | ***Util | DateUtil |
系统监控器类 | **Monitor | MemcachedMonitor |
逻辑层类 | **Service | UserService |
b POJO 类命名约定
POJO类包含了Entity、VO。POJO 类中布尔类型的变量,都不要加 is ,否则部分框架解析会引起序列化错误。
c 常规方法的命名约定
方法名
|
示例
|
批量
|
备注
|
---|---|---|---|
列表 | list***(复数) listUsers | - | 如果返回为空,则返回size=0的list,不能返回null |
创建 | create*** create createUser | batchCreate**s batchCreateUsers | |
删除 | delete** delete deleteUser | batchDelete**s batchDeleteUsers | |
更新 | update** update updateUser | batchUpdate**s batchUpdateUsers | |
统计 | count*** | batchCount*** | |
获取单个对象 | get** get getUser | batchGet**s batchGetUsers | |
获取单个对象根据某个参数 | getBy** getByName | - |
- 不要使用一个常量类维护所有常量,应该按常量功能进行归类,分开维护。如:缓存相关的常量放在类: CacheConsts 下 ; 系统配置相关的常量放在类: ConfigConsts 下。
说明:大而全的常量类,非得使用查找功能才能定位到修改的常量,不利于理解和维护。
- 常量的复用层次有五层:跨应用共享常量、应用内共享常量、子工程内共享常量、包内共享常量、类内共享常量。
- 跨应用共享常量:放置在二方库中,通常是 client . jar 中的 constant 目录下。
- 应用内共享常量:放置在一方库的 modules 中的 constant 目录下。
- 反例:易懂变量也要统一定义成应用内共享常量,两位攻城师在两个类中分别定义了表示“是”的变量:
- 类 A 中: public static final String YES = " yes " ;
- 类 B 中: public static final String YES = " y " ;
- A . YES . equals(B . YES) ,预期是 true ,但实际返回为 false ,导致产生线上问题。
- 子工程内部共享常量:即在当前子工程的 constant 目录下。
- 包内共享常量:即在当前包下单独的 constant 目录下。
- 类内共享常量:直接在类内部 private static final 定义
7)、控制语句
a 在一个 switch 块内,每个 case 要么通过 break / return 等来终止,要么注释说明程序将继续执行到哪一个 case 为止 ; 在一个 switch 块内,都必须包含一个 default 语句并且放在最后,即使它什么代码也没有。
b 在 if / else / for / while / do 语句中必须使用大括号,即使只有一行代码,避免使用下面的形式: if (condition) statements;
c 推荐尽量少用 else , if - else 的方式可以改写成:
if
(condition) {
...
return
obj;
}
boolean
existed = (file.open(fileName,
"w"
) !=
null
) && (...) || (...);
if
(existed) {
...
}
//NOT GOOD
public
int
insertUser() {
String name=request.get(
"name"
);
String password=request.get(
"password"
);
}
//GOOD
public
int
insertUser(String name,String password) {
}
二、业务规范
正例: " test " .equals(object);
反例: object.equals( " test " );
说明:推荐使用 java . util . Objects # equals (JDK 7 引入的工具类 )
说明:对于 Integer var = ?在-128 至 127 之间的赋值, Integer 对象是在IntegerCache . cache 产生,会复用已有对象,这个区间内的 Integer 值可以直接使用==进行判断,但是这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象,这是一个大坑,推荐使用 equals 方法进行判断。
说明:在方法执行抛出异常时,可以直接调用 POJO 的 toString() 方法打印其属性值,便于排查问题。
说明:公有方法是类的调用者和维护者最关心的方法,首屏展示最好 ; 保护方法虽然只是子类关心,也可能是“模板设计模式”下的核心方法 ; 而私有方法外部一般不需要特别关心,是一个黑盒实现 ; 因为方法信息价值较低,所有 Service 和 DAO 的 getter / setter 方法放在类体最后。
public
class
TimerTaskThread
extends
Thread {
public
TimerTaskThread() {
super
.setName(
"TimerTaskThread"
); ...
}
说明:注意,子线程抛出异常堆栈,不能在主线程 try - catch 到。
三、极致函数
1、不超过100行
2、嵌套层次不超过3层
例如if else try for while等这些控制代码的层次不能过深,否则可读性将会变得很差。尽量保持平级,尽早返回或跳出。
3、一个函数不超过2个功能的具体代码,可以是引用
如果函数内有多个功能的具体代码,会造成临时变量过多,并且这些变量大多是无相关的。会造成命名困难与容易引用变量出错。