java开发规范

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

一、通用规范

1、注释

总体原则是: 对外接口必须写;内部接口不建议使用 ,如果名字已经可以解释其意义,则不需要加注释,如果不能解释则可以加

1)属性注释

/** xxx **/
private String name;
2)方法里注释
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);
3)缩进采用 4 个空格,禁止使用 tab 字符。(tab字符在不同操作系统上体现不一样,可以在ide上设置tab自动转成4个空格)
4)字段与字段之间不换行
public static String name;
private int id;
5)方法与方法之间:换一行
public void method1(){
}
 
public void method2(){
}

3、命名规范

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

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

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) {
}

二、业务规范

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

三、极致函数

1、不超过100行

2、嵌套层次不超过3层

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

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

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

 
 
 
原文地址:https://www.cnblogs.com/ptw-share/p/6956881.html