Java语言规范
命名风格
- **类名:**使用 UpperCamelCase 风格,必须遵从驼峰形式,但以下情形例外:DO / BO /
DTO / VO / AO,所有单词的首字母大写 - **方法名、参数名、成员变量、局部变量:**统一使用 lowerCamelCase 风格,也都必须遵从驼峰形式,除第一个单词之外所有单词的首字母大写
- **常量:**全部大写,单词间用下划线隔开,力求语义表达完整清楚,不要嫌名字长
- **包名:**统一使用小写,点分隔符之间有且仅有一个自然语义的英语单词。包名统一使用单数形式,类名可以使用复数形式
- **POJO 类(Java对象类)中布尔类型的变量:**都不要加 is,否则部分框架解析会引起序列化错误,例如定义为基本数据类型 Boolean isDeleted;的属性,它的方法也是
isDeleted()
,RPC框架在反向解析的时候,“以为”对应的属性名称是 deleted,导致属性获取不到,进而抛出异常 - **接口:**类中的方法和属性不要加任何修饰符号(public 也不要加),保持代码的简洁性,并加上有效的 Javadoc 注释。尽量不要在接口里定义变量,如果一定要定义变量,肯定是与接口方法相关,并且是整个应用的基础常量
Tips:
- 代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束
- 代码中的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式,正确的英文方便让读者理解,即使是纯拼音也要避免采用
- 抽象类命名使用 Abstract 或 Base 开头;异常类命名使用 Exception 结尾;测试类命名以它要测试的类的名称开始,以 Test 结尾
- 如果模块、接口、类、方法使用了设计模式,在命名时体现出具体模式
- 杜绝完全不规范的缩写,避免望文不知义,使用尽量完整的单词组合来表达其意
常量定义
- 不允许任何魔法值(即未经定义的常量)直接出现在代码中
- 不要使用一个常量类维护所有常量,按常量功能进行归类,分开维护
- 如果变量值仅在一个范围内变化,且带有名称之外的延伸属性,定义为枚举类。下面正例中的数字就是延伸信息,表示星期几
- 常量的复用层次有五层:跨应用共享常量、应用内共享常量、子工程内共享常量、包内共享常量、类内共享常量。
- 跨应用共享常量:放置在二方库中,通常是 client.jar 中的 constant 目录下
- 应用内共享常量:放置在一方库中,通常是 modules 中的 constant 目录下
- 子工程内部共享常量:即在当前子工程的 constant 目录下
- 包内共享常量:即在当前包下单独的 constant 目录下
- 类内共享常量:直接在类内部 private static final 定义
代码格式
- **大括号:**左大括号前不换行,左大括号后换行,右大括号前换行,右大括号后还有 else 等代码则不换行;表示终止的右大括号后必须换行
- **空格:**左(右)小括号和字符之间不出现空格;if/for/while/switch/do 等保留字与括号之间都必须加空格;任何二目、三目运算符的左右两边都需要加一个空格;注释的双斜线与注释内容之间有且仅有一个空格;方法参数在定义和传入时,多个参数逗号后边必须加空格
- 注释:
①类、方法、成员变量的注释
/*** 类、方法、成员变量*/
对于类注释,应该完善作者、时间、类的作用等信息
②代码中的注释,使用双斜线
OOP规约
- 避免通过一个类的对象引用访问此类的静态变量或静态方法,无谓增加编译器解析成本,直接用类名来访问即可
- 相同参数类型,相同业务含义,才可以使用 Java 的可变参数,避免使用 Object
- 外部正在调用或者二方库依赖的接口,不允许修改方法签名,避免对接口调用方产生影响。接口过时必须加@Deprecated 注解,并清晰地说明采用的新接口或者新服务是什么
- Object 的 equals 方法容易抛空指针异常,应使用常量或确定有值的对象来调用
equals - 构造方法里面禁止加入任何业务逻辑,如果有初始化逻辑,请放在 init 方法中
集合处理
- 关于
hashCode
和equals
的处理,遵循如下规则:- 只要重写
equals
,就必须重写hashCode
- 因为
Set
存储的是不重复的对象,依据hashCode
和equals
进行判断,所以Set
存储的对象必须重写这两个方法 - 如果自定义对象做为
Map
的键,那么必须重写hashCode
和equals
- 只要重写
- 不要在
foreach
循环里进行元素的remove/add
操作。remove
元素请使用Iterator
方式,如果并发操作,需要对Iterator
对象加锁
Iterator
是一种设计用来遍历集合(如List
、Set
)元素的接口。使用Iterator
来移除元素是一种安全的做法,因为它内部维护了一个指向下一个要返回元素的游标。当使用Iterator
的remove()
方法来移除元素时,它能够确保集合的状态保持一致,即使在并发环境下也是如此
- 高度注意 Map 类集合 K/V 能不能存储 null 值的情况
并发处理
- 获取单例对象需要保证线程安全,其中的方法也要保证线程安全
- 创建线程或线程池时请指定有意义的线程名称,方便出错时回溯
- 线程资源必须通过线程池提供,不允许在应用中自行显式创建线程
使用线程池的好处是减少在创建和销毁线程上所花的时间以及系统资源的开销,解决资源不足的问题。如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或者“过度切换”的问题
- SimpleDateFormat 是线程不安全的类,一般不要定义为 static 变量,如果定义为static,必须加锁,或者使用 DateUtils 工具类
控制语句
- 在 if/else/for/while/do 语句中必须使用大括号。即使只有一行代码,避免采用
单行的编码方式 - 在一个 switch 块内,每个 case 要么通过 break/return 等来终止,要么注释说明程序将继续执行到哪一个 case 为止;在一个 switch 块内,都必须包含一个 default 语句并且放在最后,即使它什么代码也没有
注释规约
- 类、类属性、类方法的注释必须使用 Javadoc 规范,使用/*内容/格式,不得使用// xxx 方式
- 所有的抽象方法(包括接口中的方法)必须要用 Javadoc 注释、除了返回值、参数、异常说明外,还必须指出该方法做什么事情,实现什么功能
- 所有的类都必须添加创建者和创建日期
- 方法内部单行注释,在被注释语句上方另起一行,使用//注释。方法内部多行注释使用/* */注释,注意与代码对齐
- 所有的枚举类型字段必须要有注释,说明每个数据项的用途
- 代码修改的同时,注释也要进行相应的修改,尤其是参数、返回值、异常、核心逻辑等的修改,没有用处的的代码应删除而不是注释掉,一般注释适用于后续可能会恢复此代码的逻辑或者因为是别人写的没有备注信息,不知道代码的动机
- 特殊注释标记,请注明标记人与标记时间。注意及时处理这些标记,通过标记扫描,经常清理此类标记。线上故障有时候就是来源于这些标记处的代码
- 待办事宜(TODO):( 标记人,标记时间,[预计处理时间]):表示需要实现,但目前还未实现的功能。这实际上是一个 Javadoc 的标签,目前的 Javadoc还没有实现,但已经被广泛使用。只能应用于类,接口和方法(因为它是一个 Javadoc 标签)。
- 错误,不能工作(FIXME):(标记人,标记时间,[预计处理时间]):在注释中用 FIXME 标记某代码是错误的,而且不能工作,需要及时纠正的情况
其它规范
-
获取当前毫秒数
System.currentTimeMillis();
而不是new Date().getTime()
-
任何数据结构的构造或初始化,都应指定大小,避免数据结构无限增长吃光内存
-
注意
Math.random()
这个方法返回是double
类型,注意取值的范围 0≤x<1(能够取到零值,注意除零异常),如果想获取整数类型的随机数,不要将 x 放大 10 的若干倍然后取整,直接使用 Random 对象的nextInt
或者nextLong
方法
异常处理
- Java 类库中定义的一类
RuntimeException
可以通过预先检查进行规避,而不应该通过 catch 来处理,比如:IndexOutOfBoundsException
,NullPointerException
等等
IndexOutOfBoundsException
是一个由数组或集合的索引操作引发的异常。当尝试访问数组或列表等数据结构的索引位置超出其有效范围时,就会抛出这个异常。
NullPointerException
是在尝试使用一个未被初始化(即null)的对象时抛出的异常。这意味着你尝试调用一个null引用的方法或访问其属性。
- 对大段代码进行 try-catch,这是不负责任的表现。catch 时请分清稳定代码和非稳定代码,稳定代码指的是无论如何不会出错的代码。对于非稳定代码的 catch 尽可能进行区分异常类型,再做对应的异常处理
- 异常不要用来做流程控制,条件控制,因为异常的处理效率比条件分支低
- 捕获异常是为了处理它,不要捕获了却什么都不处理而抛弃之,如果不想处理它,请将该异常抛给它的调用者。最外层的业务使用者,必须处理异常,将其转化为用户可以理解的内容
- 有 try 块放到了事务代码中,catch 异常后,如果需要回滚事务,一定要注意手动回滚事务
MySQL数据库
建表规约
- 表达是与否概念的字段,必须使用 is_xxx 的方式命名,数据类型是 unsigned tinyint( 1 表示是,0 表示否)
- 表名、字段名必须使用小写字母或数字,禁止出现数字开头,禁止两个下划线中间只出现数字。数据库字段名的修改代价很大,因为无法进行预发布,所以字段名称需要慎重考虑
- 表名不使用复数名词
- 主键索引名为 pk字段名;唯一索引名为 uk字段名;普通索引名则为 idx_字段名
- 小数类型为
decimal
,禁止使用float
和double
- varchar 是可变长字符串,不预先分配存储空间,长度不要超过 5000,如果存储长度大于此值,定义字段类型为 text,独立出来一张表,用主键来对应,避免影响其它字段索引效率
索引规则
- 业务上具有唯一特性的字段,即使是多个字段的组合,也必须建成唯一索引
- 超过三个表禁止 join(连接)。需要 join 的字段,数据类型必须绝对一致;多表关联查询时,保证被关联的字段需要有索引
- 在 varchar 字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据实际文本区分度决定索引长度即可
SQL语句
- 不要使用 count(列名)或 count(常量)来替代 count(),count()是 SQL92 定义的标准统计行数的语法,跟数据库无关,跟 NULL 和非 NULL 无关
- 禁止使用存储过程,存储过程难以调试和扩展,更没有移植性
- 数据订正时,删除和修改记录时,要先 select,避免出现误删除,确认无误才能执行更新语句
参考文档:
《阿里巴巴Java开发手册(终极版)》免费在线阅读_藏经阁-阿里云开发者社区 (aliyun.com)
《阿里巴巴Android开发手册》免费在线阅读_藏经阁-阿里云开发者社区 (aliyun.com)
本篇博客只讲述了开发过程当中的基本语言规范,想要更了解可以看以上参考文档,会有更多的规范内容。
到这里就结束了!