Java开发规范

Java开发规范

随着《阿里巴巴Java开发手册》的公开,从新又掀起一股编码规范的风口。结合《华为java编程规范》以及团队内部的实践,咱们也作了一段开发规范。不求最全,但求有效。javascript

里面的规范,暂时只分两类。“强制”,即若是违反就不能使用级别。好比说,在codereview有遇到 ,那就会直接把pull request打回去,拒绝合并到开发者稳定分支上。“推荐”,即建议怎么作,可是不强制,根据不一样的水平能够作一些参考。php

通用规范

全部的状况下都通用css

一、 【强制】命名所有使用英文,禁止中文或者中英混合。项目名除外,由于有的项目是按域名来命名的,域名自己有多是中文拼音。html

例子java

域名:kecheng.xxx.com
项目名:xxx-web-kecheng

二、 【强制】禁止使用缩写,除非提供一个缩写列表git

反例web

# 这里的t究竟是什么意思?topic_id?仍是teacher_id?
字段:t_id

三、 【强制】禁止出现除了后缀或者前缀3个单词。若是超过3个,说明想表达的职责太多,能够拆分或者封装。算法

编程语言

这里主要指的是Java语言,其余的语言也能够借鉴这些准则sql

一、 【强制】须要有统一的后缀或者前缀。为了一看类名,就知道这个类干什么的。数据库

前缀列表:

  • 抽象类(Abstract)
  • 接口(I)

正例

接口:IViewTag
抽象类:AbstractViewTag  
具体实现类:UserViewTag

后缀列表:

  • 实体(Entity)。数据库持久对象。
  • 表单(Form)。用于封装、校验http参数。
  • 数据传输对象(DTO)。用于暴露接口的返回数据
  • 基础服务(BaseService)。单实体能够自描述的服务。
  • 业务服务(BusinessService)。集合多个单实体的服务。
  • 页面服务(ViewService)。涉及到视图页面的服务。
  • 模块(Module)。http入口模块。
  • 异常(Exception)
  • 工具(Util)
  • 枚举(Enum)
  • 视图标签(ViewTag)
  • ....(其余的,好比:Filter之类)

正例

实体:UserEntity
基础服务:UserBaseService 
业务服务:AuthorityBusinessService

二、 【强制】全部参与业务的类禁止使用内部类。

属性

一、 【强制】常量必须是:大写+下划线,禁止多个单词连在一块儿

正例

private final static String PAGE_SIZE=10;

反例

private final static String PAGESIZE=10;
private final static String pageSize=10;

二、 【强制】布尔类型禁止添加"is"前缀。部分框架解析会引发序列化错误。

反例

# 对应的getter和setter为:isRead和setRead
private boolean isRead

正例:

# 对应的getter和setter为:isRead和setRead
private boolean read;

三、 【强制】计数器禁止使用复数

反例

private int readCounts;

正例:

private int readCount;

四、 【强制】自描述属性里不要出现类名的描述

反例

#UserEntity类
private String userName;
private int userAge;

正例

#UserEntity类
private String name;
private int age;

五、【强制】关联其余实体的属性命名规则:对应的实体去掉后缀+用途

正例

属性名:teacherId ,对应的实体是TeacherEntity
属性名:favorCount,对应的实体是FavorEntity

反例

属性名:tId。根本不知道是哪一个实体的外键。有多是Teacher有多是Topic,还得猜半天

六、 【强制】禁止经过定义定义成常量(1,2)来维护类型值,须要经过枚举

反例

private final static int SUCESS=1;
private final static int FAIL=2;

正例

定义一个枚举

方法

一、 【强制】接口里的方法禁止有修饰符。

反例

#接口里的方法
public void eat();

正例

#接口里的方法
void eat();

二、 【推荐】方法参数必须使用final来修饰。final可提升程序响应效率。能够经过Eclipse的cleanup来实现。

正例

public void eat(final int size);

反例

public void eat(int size);

三、 【强制】每个方法参数都须要被处理。module层的方法里的对象参数能够不判空,由于架构已经作处理了,不可能为空。

被处理指的是:

  • 抛异常。
  • 直接返回。
  • 有对应的业务处理逻辑。

例子

public void add(long userId,String content){
    //异常验证
    ExceptionUtil.checkId(userId,"用户id")
    //直接返回
    if(Util.isEmpty(content)){
        return ;
    }
}

public List<CourseEntity> list(int type){
    Cnd cnd = Cnd.limit();
    //有对应的业务逻辑处理
    if(type>0){
        cnd.and("type","=",type);
    }
    return dbDao.query(CourseEntity.class,cnd,null);
}

四、 【强制】同一个类里有多个一致的参数(3个以上)的方法,须要抽取接口或者经过实体来承载

反例

public FavorEntity add(int type,long sourceId,long userId);
public FavorEntity delete(int type,long sourceId,long userId);

正例

public FavorEntity add(IFavor favor);
public FavorEntity delete(IFavor favor);

五、 【强制】方法名必须是动词或者动宾。http接口须要知明达意,能够不按这个规则。好比:mycourse,home,banner

方法命名格式:

  • is+动词|形容词
  • 动词【+名词|形容词】

例子

public void isSucess();
public void on();
public void sendEmail();

统一命名列表:

  • add 新增
  • update 修改
  • delete 删除
  • get 获取单个对象
  • list 获取集合对象
  • getMap 获取map数据
  • count 数量

方法前缀后缀命名说明:

原则上不添加后缀,若是添加后缀的话,若是有添加,命名格式为:updatexxxx4yyyyByzzzz

  • xxxx:表示对象的属性
  • yyyy:表示查询的条件(根据自描述属性查询)
  • zzzz:表示查询的条件(根据其余描述属性查询)

例子

--xxxx状况:用户
public void updateName();();
public void updateNickName();
--yyyy状况:资讯
public List<NewsEntity> list4Latest();
public List<NewsEntity> list4Top();     
--zzzz状况:课程
public List<CourseEntity> listByTeacher();
public List<CourseEntity> listByKnowledge();

--综合使用
public List<CourseEntity> listCourse4TopByTeacher();

六、 【强制】一个方法里代码行数不能超过1屏(即30行)。通常来讲超过30的行,业务关注点、复杂数比较高,很难维护。超过30行须要封装方法

七、 【强制】局部变量命名不能有连续的名称。连续的命名不具备可维护性。每一个变量都须要有清晰的概念。

反例

String head1;
String head2;

正例

String title;
String content;

八、 【强制】禁止有任何魔鬼数据独立存在。能够定义一个有含义的变量来承载

反例

if(type ==1){
    //审核成功 
    下面15行代码
}

正例

private final static int SUCESS=1;
....
if(type ==SUCESS){
    下面15行代码
}

九、 【强制】判断表达式要使用布尔变量或者封装方法。表达式是变化点。在维护的时候,表达式不知名达意。

反例

if(user!=null&&!Util.isEmpty(user.name)&&!Util.isEmpty(user.provicne)){
    //下面15行代码
}

正例

if(isFilledBaseInfo(user)){
    //下面15行代码
}

十、【强制】if()...else if()...else个数不能多于4个,嵌套不能深于3层

能够经过如下的方法来消除:

  • 设计模式
  • 抽取方法
  • 使用return

反例

if(isAdmin()){
    ...
}else if(isTeacher()){
    ...
}

正例

if(isAdmin()){
    ...
    return;
}
if(isTeacher()){
    ...
    return;
}

十一、 【推荐】采用防护式编程,先判断错误的业务,而后再写正确的业务。防护式编程结构清晰分明:先把全部错误穷举,而后集中处理正确逻辑。

反例

if(null!=user && user.hasAuth()){
    正确逻辑
}

正例

if(null==user || !user.hasAuth()){
    return;
}
正确逻辑

十二、 【推荐】for里不建议写io。io包括:数据库、缓存,文件读写等

1三、 【强制】多个不一样的结构(业务相近的代码),须要有且只有一个空行

反例

long userId = fetchUser.getCurrentUserId();
Sql sql = latentCustomerQueryForm.pager(sqlManager);
Map<String, Object> map = FormUtil.list(dbDao, sql, pager);
List<DictInfoEntity> grades = dictBaseService.listDict(DictInfoEnum.GRADE.stringKey());
List<DictInfoEntity> infoOrigins = dictBaseService.listDict(DictInfoEnum.INFOORIGIN.stringKey());
map.put("queryForm", latentCustomerQueryForm);
map.put("grades", grades);
map.put("infoOrigins", infoOrigins);
return map;

正例

long userId = fetchUser.getCurrentUserId();
Sql sql = latentCustomerQueryForm.pager(sqlManager);
Map<String, Object> map = FormUtil.list(dbDao, sql, pager); 

List<DictInfoEntity> grades = dictBaseService.listDict(DictInfoEnum.GRADE.stringKey());
List<DictInfoEntity> infoOrigins = dictBaseService.listDict

map.put("queryForm", latentCustomerQueryForm);
map.put("grades", grades);
map.put("infoOrigins", infoOrigins);
return map;

1四、 【推荐】不参与计算的变量不要定义变量

反例

long userId = fetchUser.getCurrentUserId();
Sql sql = latentCustomerQueryForm.pager(sqlManager);
Map<String, Object> map = FormUtil.list(dbDao, sql, pager); 

List<DictInfoEntity> grades = dictBaseService.listDict(DictInfoEnum.GRADE.stringKey());
List<DictInfoEntity> infoOrigins = dictBaseService.listDict(DictInfoEnum.INFOORIGIN.stringKey());

map.put("queryForm", latentCustomerQueryForm);
map.put("grades", grades);
map.put("infoOrigins", infoOrigins);
return map;

正例

long userId = fetchUser.getCurrentUserId();
Sql sql = latentCustomerQueryForm.pager(sqlManager);
Map<String, Object> map = FormUtil.list(dbDao, sql, pager); 

map.put("grades", dictBaseService.listDict(DictInfoEnum.GRADE.stringKey()));
map.put("infoOrigins", dictBaseService.listDict(DictInfoEnum.INFOORIGIN.stringKey()));
return map;

1五、 【强制】若是有捕获异常,必须有对应的处理业务。若是没有对应的处理业务,不要捕获,能够直接throw,让架构统一处理

你本身catch,确定不但愿用户看到错误日志,那么 从用户那边看到是正常业务。catch了什么都没干,用户每每看到的是什么都没发生,他会觉得网站挂了或者功能快。

1六、 【强制】禁止使用exception.getMessge()处理错误信息。应该使用exception.toString()。由于exception.getMessage(),在npe抛出异常的时候,什么信息都不显示。

反例

} catch (Exception e) {
        logger.error(e.getMessage());
    }

正例

} catch (Exception e) {
        logger.error(e.toString());
    }

1七、 【强制】禁止使用System.out.print。统一使用Eclipse的log4e插件生成日志(不要定义具体的日志实现,要定义的是slf4j的接口)

1八、 【推荐】公开的接口,一旦发布成稳定版,禁止修改方法签名(方法名,参数)

若是要修改,须要提供新的接口,老的不能修改。老的接口上添加@Deprecated注解而且使用@see清晰的说明采用新接口或新服务是什么

由于一修改方法签名。好比:js调用可能就报错了,功能就没办法使用;工具类接口一变,其余项目就会报错了,没办法向下兼容。

1九、 【推荐】方法放置顺序:public-->protected-->private。一个类,每每使用者更关注的是public的。构造方法、重载方法、雷同方法,按顺序放在一块儿

注释

一、 【强制】格式结构统一使用eclipse模板,禁止自定义。

二、 【强制】类、方法、属性都必须有注释。若是实在来不及,能够先生成TODO。由于能够经过TODO视图,把注解补回来。

三、 【强制】类上必需要有做者,若是有修改,还要添加上修改者,若是有结队也要写上。要有用户名还要有邮箱

例子

/** * 字典 * * @author ZhuangJunxiang(529572571@qq.com) * @version 2017-03-06 */

四、 【强制】注释要直译,描述要写算法或者思路或者注意事项。不要在注释上代码里的每一行彻底暴露出来,使用者根本不关注实现。

反例

/** * 学生分页查询 #方法里根据没有学生。。。。 * * @param page 分页对象 * @param studentForm 学生 * @return 分页对象 */
public Page<Map<String, Object>> findPageList(Page<Map<String, Object>> page, StudentForm studentForm) {

五、 【强制】方法里禁止写注释。不要有多余的注释,让变量和属性自描述或者抽取方法。若是有算法写到方法注释上。

反例

//填充基本信息
fillBaseInfo();
//填充帐号信息
fillAccoutInfo();

六、 【强制】方法里禁止注释掉代码。统一经过版本控制软件(git)来解决。逻辑是正确的,可是如今暂时不能使用,能够暂时注释,可是必须写上TODO。

TODO格式: TODO 标记人 缘由

例子

//TODO 张三 当前用户还未处理,由于登陆尚未调通
//long userId = fetchUser.getCurrentUserId();
long userId = 1L;
....

数据库

这里主要指的是MySQL,其余的数据库也能够借鉴这些准则

一、【强制】统一使用表名命名规范

表名规范:分层+项目名缩写+下划线+实体名(小写字母)【+下划线+实体名(小写字母)+rel】

例子

表名:bc_course  对应的信息:基础服务层,项目缩写为c里对应的CourseEntity实体对应的表

表名:sc_course_knowledge_rel 对应的信息:综合服务层,项目缩写为c里对应的CourseEntity实体和KnowledgeEntity实体的关系表

分层:

  • 基础服务:b
  • 综合服务:s
  • webapp服务:a

表的种类:

  • 映射实体的表:前缀_实体名(小写字母)。实体里有多个单词,用下划线隔开。
  • 关系表:前缀_实体名1(小写字母)_实体名2(小写字母)_rel。同一个实体里有多个单词,拼接在一块

例子

bc_course_group -->CourseGroupEntity
sc_coursegroup_coursepack_rel -->CourseGroupEntity和CoursePackEntity的关系表

二、 【强制】统一使用innoDB引擎。

三、 【推荐】表名不要关联其余表名信息
反例

bc_course
bc_course_video
bc_course_video_study_log

正例

bc_course
bc_video
bc_study_log

索引

一、 【强制】业务上具备惟一特性的字段,即便是组合字段,必须使用惟一索引。好比: 用户名,编号等。若是没有添加惟一索引,即便在应用层作了很是完善的校验和控制,只要没有惟一索引,必然有脏数据

二、 【强制】惟一索引命名:uk_字段名,普通索引命名:idx_字段名

三、 【强制】禁止对text定义索引。若是有对这类字段搜索的需求,能够经过全文索引方法来实现功能。

四、 【推荐】varchar定义索引长度。通常有搜索的话,用户也不会输入太多字。长度统一10为倍数,不要超过50

字段

一、 【强制】主键禁止使用自增。不一样库同步数据的时候,会出问题。影响插入性能。

二、 【强制】字段所有禁止为空。为空的话,很容易在使用的时候出现npe。若是能够不填,经过默认值方法来处理。

三、 【强制】禁止使用外键,只能在概念和应用层次使用外键

外键的字段命名:表名去除前缀+id

四、 【强制】禁止使用枚举、集合类型

五、 【强制】禁止在数据库使用blog存在文件。数据库只存相对的url路径

六、 【强制】类型使用规范

  • 布尔:bit
  • 时间(精确到天):date
  • 时间(精确到秒):datetime
  • 浮点:deciaml
  • 字符串(长度小于10或者长度大于10可是长度相同):char
  • 字符串(长度为10~5000,长度不相同):varchar
  • 字符串(富文本):text

七、 【强制】必有字段

  • 主键
  • 建立时间
  • 修改时间
  • 假删状态(若是是资源数据必须有,若是是关系数据禁止有)

八、 【推荐】能够适合添加冗余数据,这样能够增快查询数据。

冗余类型:

  • 计数器、计分器等统计数据
  • 一旦生成不会修改的数据

九、 【推荐】字段顺序:自描述-->关联其余表的描述-->功能性-->必有字段

注释

一、 【强制】表名或者字段注释的格式:直译【(补充说明)】

反例

表名:t_first_login,注释:本表用于处理河北联通卡的临时业务问题,记录已经使用web登陆过的卡号

正例

表名:t_first_login,注释:首次登陆(用于处理河北联通卡的临时业务问题,记录已经使用web登陆过的卡号)

二、 【强制】禁止带“表”,“数据”等多余的字眼

反例

表名:aw_input_batch,注释:输入批次表
表名:t_admission_110000,注释:北京院校专业数据

三、 【推荐】若是类型字段,有变动,同步注释

例子

status   状态(0:成功,1:失败)
//过了一段时间,又多了一个冻结的状态
status   状态(0:成功,1:失败,2:冻结)

sql

一、 【强制】禁止select *。数据库查看执行时间性能没有响应。可是返回的数据量会变大,对网络开销有影响,最终仍是会影响性能,并且也会影响数据库的二进步日志

二、 【强制】使用select count(*)。select count(name) 不记录null的行数。并且官方已经澄清过,不影响性能 。

反例

select count(1)
select count(id)

三、 【强制】使用sum函数时,必须使用IFNULL(sum(),0)。若是sum函数没有查到结果返回null,容易出现npe。

四、 【推荐】禁止出现or。能够经过使用in或者unit all来替换

五、 【推荐】order by的场景,建立索引时order by 后面的字段也必须是组合索引的一部分,而且放在索引顺序的最后,避免出现file_sort

正例

where a=? and b=? order by c; 索引:a_b_c

六、 【推荐】建立组合索引时,区分度最高的放在最左边

正例

where a=? and b=?  若是a几乎接近惟一,那么只要建idx_a便可。

七、 【推荐】禁止更新表的全部字段,必须指定要更新的字段

禁止项

原则上,禁止采用这些技术。除非架构上有这些考虑。

  • 存储过程
  • 外键
  • 视图
  • 触发器
  • 分库、分表、分区。(单表行数超过500万行或者单表容量超过2GB,才推荐进行分库分表)

工程|项目

项目

语法:平台-分层职责-服务名称

例子

# uxuexi是平台,web是分层,course是服务名称(由于是web,因此对应的是子域名),对应的域名是course.uxuexi.com
uxuexi-web-course
# uxuexi是平台,business是分层,sso是服务名称
uxuexi-business-sso
# uxuexi是平台,base是分层,course是服务名称
uxuexi-base-course
# we是平台(由于是通用的,没有对应的域名,因此使用we),business是分层,sso是服务名称
we-business-sso
# we是平台(由于是通用的,没有对应的域名,因此使用we),core是分层,db是服务名称
we-core-db

一、 平台

使用的域名去掉组织后缀。

例子

域名:www.uxuexi.com
-------
子域名:www
平台名:uxuexi
组织:com

二、 分层职责

  • core(能力层。与具体业务无关,提供能力)
  • base(基础服务层。能够独立存在,有且只有一个具备实际意义的服务,不依赖于其余的服务)
  • business(业务服务层。依赖多个基础服务,通常是一个流程性的服务)
  • webapp(应用层。对互联网用户提供直接服务)

三、 服务名称

若是是web项目,使用子域名看成服务名称。其余的项目,根据职责划分来自行命名。

分包

java源码

一、 根目录

语法:域名组织-项目名。若是web层项目,直接使用对应的域名倒置便可。

例子

# web层项目,直接使用对应的域名倒置便可
项目名:uxuexi-web-course 
根目录为:com.uxuexi.course
# 其余层项目,使用:域名组织+项目名
项目名:uxuexi-business-sso 
根目录为:com.uxuexi.business.sso

二、 java包

语法:分包【+子模块】+文件(类+后缀)。其中子模块是参考业务的包才有,通用功能能够没有子模块。

分包清单:

  • module:http路由,负责根据不一样的业务跳转到不一样的url。
  • form:负责http参数的封装、验证、传输。负责sql的编写
  • entity:数据库持久对象。数据的持久及对象自己业务的实现
  • dto:接口返回的实体
  • service:逻辑单元。逻辑处理或者叫计算单元
  • util:工具
  • enums:枚举
  • vt:视图标签
  • ...

有子模块的业务包有:module,form,entity,dto,service。若是有通用的逻辑,可使用common子模块包名

例子

包名:module.student.course ,类名:StudentCourseModule
包名:module.user,类名:UserModule
包名:util,类名:StringUtil

资源文件

一、 根目录

resources

二、 sql包

和service及form的包名一致,文件名和java调用的类名一致

例子

# java 
# com.uxuexi.www 根目录
# module 分包
# student.course 子模块
# StudentCourseViewService.java 文件
com.uxuexi.wwww.module.student.course.StudentCourseViewService.java

# sql
# resources 根目录
# sql 分包
# student.course 子模块
# StudentCourseViewService.sql 文件
resources.sql.student.course.StudentCourseViewService.sql

视图文件

一、 根目录

WEB-INF

二、 视图包

module类单词小写分隔,文件名和module里的方法名一致

例子

# java 
# com.uxuexi.www 根目录
# module 分包
# student.course 子模块
# StudentCourseModule 文件
# list 方法
com.uxuexi.wwww.module.student.course.StudentCourseModule.list()

# 视图
# WEB-INF 根目录
# student.course 子模块
# list.jsp 文件
WEB-INF.student.course.list.jsp

完整例子





相关文章
相关标签/搜索