java开发规范

主要参考了阿里巴巴开发规范,特此说明java

1、通用规范

一、注释

整体原则是: 对外接口必须写;内部接口不建议使用 ,若是名字已经能够解释其意义,则不须要加注释,若是不能解释则能够加数据库

1)属性注释设计模式

/** xxx **/
private  String name;
2)方法里注释
public  void  setName(String name){
  //xxx
  do ();
}

二、文件结构

1)类的成员顺序:public > private > final > static > 实例成员;类结构:成员 > 构造方法 > 静态方法 > 实例方法api

说明:一般使用者会更关注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 在括号前不要换行,以下反例app

method(args1, args2, args3, ...
     ,argsX);
3)缩进采用 4 个空格,禁止使用 tab 字符。(tab字符在不一样操做系统上体现不同,能够在ide上设置tab自动转成4个空格)
4)字段与字段之间不换行
public  static  String name;
private  int  id;
5)方法与方法之间:换一行
public  void  method1(){
}
 
public  void  method2(){
}

三、命名规范

不能使用拼音进行命名,统一使用准确的英文进行命名框架

不采用简写方式命名(除公认的经常使用简写,或公司/小组字典表有描述)。命名过长比不能理解更好异步

1)、包名

采用单数命名。例如util,entity,service

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
}
5)、方法命名
  • 方法名命名规则:
  1. 动词:init,validate,pay等
  2. 动词+介词+(宾语):compareTo,getById等
  3. 动宾短语(表示动做):createUser,publishPrivilege
  4. 谓表短语(表示状态):isClosed,isUserExisted,canUserBeDeleted等
  5. 接口类中的方法和属性不要加任何修饰符号 (public 也不要加 ,保持代码的简洁性)

  • 单复数的使用,对于一些动做须要操做多个对象,方法名要经过名词复数反映出来,例如:deleteOrders(删除订单,可能多个) 
  • 若是一个方法设计两个动做或对象,用“And”链接,如:createProductAndTag,但通常状况下,不推荐一个方法作多于一件事情 
  • 不要使用简写,除非是公司级别或者业界已经通用的约定或字典表定义表示 ,好比I18n,则可使用。由于简写很难阅读,容易误解,宁愿方法名稍微长一些,也要让方法名用正确的短语来表述,因为一个方法通常不建议作多于一件事情,因此方法名通常不会太长 
  • 一些Java业界约定俗成的方法命名:
  1. 与…进行比较:compareTo
  2. 获取单例对象:getInstance
  3. 是否相等:equals
  4. 初始化:init
  • 对于dao层,其名称可省略所属类的名称,如:
public  interface  UserDao {
  int  createUser(User user);  //NOT GOOD
  int  create(User user);  //GOOD
}
6)、系统命名约定
接口、类的命名约定 
 
类名
命名
示例
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 -  
注:
. 若是类名已经包含一些名称,方法和操做能够不写响应的名称,例如UserDao 的方法get 而不用getUser 
. 只读方法,不能作修改操做,例如get*** list*** paged*** search***
 
d 系统常量命名约定
  • 不要使用一个常量类维护全部常量,应该按常量功能进行归类,分开维护。如:缓存相关的常量放在类: CacheConsts 下 ; 系统配置相关的常量放在类: ConfigConsts 下。

  说明:大而全的常量类,非得使用查找功能才能定位到修改的常量,不利于理解和维护。

  • 常量的复用层次有五层:跨应用共享常量、应用内共享常量、子工程内共享常量、包内共享常量、类内共享常量。
  1.  跨应用共享常量:放置在二方库中,一般是 client . jar 中的 constant 目录下。
  2. 应用内共享常量:放置在一方库的 modules 中的 constant 目录下。
  3. 反例:易懂变量也要统必定义成应用内共享常量,两位攻城师在两个类中分别定义了表示“是”的变量:
  4. 类 A 中: public static final String YES = " yes " ;
  5. 类 B 中: public static final String YES = " y " ;
  6. A . YES . equals(B . YES) ,预期是 true ,但实际返回为 false ,致使产生线上问题。
  7. 子工程内部共享常量:即在当前子工程的 constant 目录下。
  8. 包内共享常量:即在当前包下单独的 constant 目录下。
  9. 类内共享常量:直接在类内部 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;
}
逻辑上超过 3 层的 if-else 代码可使用卫语句,或者状态模式来实现。
卫语句就是把复杂的条件表达式拆分红多个条件表达式,好比一个很复杂的表达式,嵌套了好几层的if - then-else语句,转换为多个if语句,实现它的逻辑,这多条的if语句就是卫语句.
d 不要在条件判断中执行其它复杂的语句,如下是正例
boolean  existed = (file.open(fileName,  "w" ) !=  null ) && (...) || (...);
if  (existed) {
     ...
}
e 循环体中的语句要考量性能
如下操做尽可能移至循环体外处理,如定义对象、变量、获取数据库链接,进行没必要要的 try - catch 操做 ( 这个 try - catch 是否能够移至循环体外 ) 。
f 尽可能写无状态的方法或者/类,如需用到值能够经过参数方式传递,较少直接引用
//NOT GOOD
public  int  insertUser() {
    String name=request.get( "name" );
    String password=request.get( "password" );
}
//GOOD
public  int  insertUser(String name,String password) {
}

2、业务规范

一、全部的覆写方法,必须加@ Override 注解。
二、不能使用过期的类或方法。
三、Object 的 equals 方法容易抛空指针异常,应使用常量或肯定有值的对象来调用equals 。
正例: " test " .equals(object);
反例: object.equals( " test " );
说明:推荐使用 java . util . Objects # equals (JDK 7 引入的工具类 )
四、全部的相同类型的包装类对象之间值的比较,所有使用 equals 方法比较。
说明:对于 Integer var = ?在-128 至 127 之间的赋值, Integer 对象是在IntegerCache . cache 产生,会复用已有对象,这个区间内的 Integer 值能够直接使用==进行判断,可是这个区间以外的全部数据,都会在堆上产生,并不会复用已有对象,这是一个大坑,推荐使用 equals 方法进行判断。
五、定义 DO / DTO / VO 等 POJO 类时,不要设定任何属性默认值。
六、POJO 类必须写 toString 方法。使用 IDE 的中工具: source > generate toString时,若是继承了另外一个 POJO 类,注意在前面加一下 super . toString 。
说明:在方法执行抛出异常时,能够直接调用 POJO 的 toString() 方法打印其属性值,便于排查问题。
七、当一个类有多个构造方法,或者多个同名方法,这些方法应该按顺序放置在一块儿,便于阅读。
八、类内方法定义顺序依次是:公有方法或保护方法 > 私有方法 > getter / setter方法。
说明:公有方法是类的调用者和维护者最关心的方法,首屏展现最好 ; 保护方法虽然只是子类关心,也多是“模板设计模式”下的核心方法 ; 而私有方法外部通常不须要特别关心,是一个黑盒实现 ; 由于方法信息价值较低,全部 Service 和 DAO 的 getter / setter 方法放在类体最后。
九、在getter / setter 方法中,尽可能不要增长业务逻辑,增长排查问题的难度。
十、循环体内,字符串的链接方式,使用 StringBuilder 的 append 方法进行扩展。
十一、任何类、方法、参数、变量,严控访问范围。过宽泛的访问范围,不利于模块解耦,变量做用域太大,若是无限制的处处跑,那么你会担忧的
十二、建立线程或线程池时请指定有意义的线程名称,方便出错时回溯。尽可能使用线程池,线程池须要用公共包中线程池工具进行生成。
public  class  TimerTaskThread  extends  Thread {
     public  TimerTaskThread() {
     super .setName( "TimerTaskThread" ); ...
}
1三、高并发时,同步调用应该去考量锁的性能损耗。能用无锁数据结构,就不要用锁 ; 能锁区块,就不要锁整个方法体 ; 能用对象锁,就不要用类锁。
1四、使用 CountDownLatch 进行异步转同步操做,每一个线程退出前必须调用 countDown方法,线程执行代码注意 catch 异常,确保 countDown 方法能够执行,避免主线程没法执行至 await 方法,直到超时才返回结果。
说明:注意,子线程抛出异常堆栈,不能在主线程 try - catch 到。
1五、全部的类都必须添加建立者信息
1六、方法内部单行注释,在被注释语句上方另起一行,使用//注释。方法内部多行注释使用/* */注释,注意与代码对齐。
1七、Java 类库中定义的一类 RuntimeException 能够经过预先检查进行规避,而不该该经过 catch 来处理,好比: IndexOutOfBoundsException , NullPointerException 等等。
1八、异常不要用来作流程控制,条件控制,由于异常的处理效率比条件分支低。
1九、对大段代码进行 try - catch ,这是不负责任的表现。 catch 时请分清稳定代码和非稳定代码,稳定代码指的是不管如何不会出错的代码。对于非稳定代码的 catch 尽量进行区分异常类型,再作对应的异常处理。
20、捕获异常是为了处理它,不要捕获了却什么都不处理而抛弃之,若是不想处理它,请将该异常抛给它的调用者。最外层的业务使用者,必须处理异常,将其转化为用户能够理解的内容。
2一、对于公司外的 http / api 开放接口必须使用“错误码” ; 而应用内部推荐异常抛出 ; 跨应用间 RPC 调用优先考虑使用 Result 方式,封装 isSuccess 、“错误码”、“错误简短信息”。
2二、定义时区分 unchecked / checked 异常,避免直接使用 RuntimeException 抛出,更不容许抛出 Exception 或者 Throwable ,应使用有业务含义的自定义异常。推荐业界已定义过的自定义异常,如: DAOException / ServiceException 等。
2三、一个类中有多个 public 方法,都须要进行数行相同的参数校验操做,这个时候请抽取:private boolean checkParam(DTO dto) {...}
2四、不容许直接拿 HashMap 与 Hashtable 做为查询结果集的输出。
 

3、极致函数

一、不超过100行

二、嵌套层次不超过3层

例如if else try for while等这些控制代码的层次不能过深,不然可读性将会变得不好。尽可能保持平级,尽早返回或跳出。

三、一个函数不超过2个功能的具体代码,能够是引用

若是函数内有多个功能的具体代码,会形成临时变量过多,而且这些变量大可能是无相关的。会形成命名困难与容易引用变量出错。

相关文章
相关标签/搜索