Java开发规范(一)

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

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

通用规范

所有的情况下都通用

1、 【强制】命名全部使用英文,禁止中文或者中英混合。项目名除外,因为有的项目是按域名来命名的,域名本身有可能是中文拼音。

例子:

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

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

反例:

# 这里的t到底是什么意思?topic_id?还是teacher_id?
字段:t_id

3、 【强制】禁止出现除了后缀或者前缀3个单词。如果超过3个,说明想表达的职责太多,可以拆分或者封装。

编程语言

这里主要指的是Java语言,其他的语言也可以借鉴这些准则

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

前缀列表:

  • 抽象类(Abstract)
  • 接口(I)
    正例:
接口:IViewTag
抽象类:AbstractViewTag  
具体实现类:UserViewTag

后缀列表:

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

2、 【强制】所有参与业务的类禁止使用内部类。

属性

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

正例:

private final static String PAGE_SIZE=10;

反例:

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

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

反例:

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

正例:

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

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

反例:

private int readCounts;

正例:

private int readCount;

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

反例:

#UserEntity类
private String userName;
private int userAge;

正例:

#UserEntity类
private String name;
private int age;

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

正例:

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

反例:

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

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

反例:

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

正例:

定义一个枚举

方法

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

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

正例

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

2、 【推荐】方法参数必须使用final来修饰。final可提高程序响应效率。可以通过Eclipse的cleanup来实现。
正例

public void eat(final int size);

反例

public void eat(int size);

3、 【强制】每一个方法参数都需要被处理。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);
}

4、 【强制】同一个类里有多个一致的参数(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);

5、 【强制】方法名必须是动词或者动宾。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();

6、 【强制】一个方法里代码行数不能超过1屏(即30行)。一般来说超过30的行,业务关注点、复杂数比较高,很难维护。超过30行需要封装方法
7、 【强制】局部变量命名不能有连续的名称。连续的命名不具有可维护性。每个变量都需要有清晰的概念。
反例

String head1;
String head2;

正例

String title;
String content;

8、 【强制】禁止有任何魔鬼数据独立存在。可以定义一个有含义的变量来承载
反例

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

正例

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

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

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

正例

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

10、【强制】if()...else if()...else个数不能多于4个,嵌套不能深于3层
可以通过以下的方法来消除:

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

反例

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

正例

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

11、 【推荐】采用防御式编程,先判断错误的业务,然后再写正确的业务。防御式编程结构清晰分明:先把所有错误穷举,然后集中处理正确逻辑。
反例

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

正例

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

12、 【推荐】for里不建议写io。io包括:数据库、缓存,文件读写等
13、 【强制】多个不同的结构(业务相近的代码),需要有且只有一个空行
反例

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;

14、 【推荐】不参与计算的变量不要定义变量
反例

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;

15、 【强制】如果有捕获异常,必须有对应的处理业务。如果没有对应的处理业务,不要捕获,可以直接throw,让架构统一处理
你自己catch,肯定不希望用户看到错误日志,那么 从用户那边看到是正常业务。catch了什么都没干,用户往往看到的是什么都没发生,他会以为网站挂了或者功能快。

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

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

正例

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

17、 【强制】禁止使用System.out.print。统一使用Eclipse的log4e插件生成日志(不要定义具体的日志实现,要定义的是slf4j的接口)
18、 【推荐】公开的接口,一旦发布成稳定版,禁止修改方法签名(方法名,参数)
如果要修改,需要提供新的接口,老的不能修改。因为一修改方法签名。
比如:js调用可能就报错了,功能就没办法使用;工具类接口一变,其他项目就会报错了,没办法向下兼容。
19、 【推荐】方法放置顺序:public-->protected-->private。一个类,往往使用者更关注的是public的。构造方法、重载方法、雷同方法,按顺序放在一起

欢迎加入学习交流群569772982,大家一起学习交流。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容