1. 数据库表设计
- Rule 1. 【强制】表名小写,多个word之间用英文下横线_分隔
- Rule 2. 【强制】表名普通表前缀t_;临时表tmp_;备份表bak_;视图v_;主键pk_;外键fk_;唯一索引uix_;普通索引idx_
- Rule 3. 【强制】关系表统一用relation结尾
- Rule 4. 【强制】表名和业务字段必须添加备注
- Rule 5. 【强制】每个表必须包含主键id,del_flag, app_id, update_time, update_id, create_time, create_id 字段,创建时间和更新时间在数据库控制,id自动生成
创建sql如下
CREATE TABLEpart_demo
(id
bigint NOT NULL COMMENT 'id',del_flag
tinyint NOT NULL COMMENT '删除标识0未删除1删除',app_id
int NOT NULL COMMENT 'plm:1,ppm:2,pim:3,alm:4',update_time
timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',update_id
bigint NOT NULL DEFAULT '0' COMMENT '更新用户',create_time
timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',create_id
bigint NOT NULL DEFAULT '0' COMMENT '创建用户',
PRIMARY KEY (id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='物料demo表' - Rule 6. 【强制】关联表涉及的关联字段,必须添加索引,且设置为非空
2. 命名规约
- Rule -1. 【强制】方法命名规则,查询getXXX增加addXXX修改modifyXXX删除delete导入importXXX导出exportXXX
- Rule 0. 【强制】dubbo 的Provider 的方法,不要出现getXXXX 返回值为void 的方法
- Rule 1. 【强制】禁止拼音缩写
- Rule 2. 【强制】禁止使用非标准的英文缩写
反例: AbstractClass 缩写成 AbsClass;condition 缩写成 condi - Rule 3. 【强制】禁用其他编程语言风格
- Rule 4. 【推荐】命名要准确,不要嫌长
- Rule 5. 【推荐】包名全部小写,也不要使用下划线
- Rule 6. 【强制】常量命名全大写,单词间用下划线隔开。力求语义表达完整清楚,不要嫌名字长
正例: MAX_REQUEST_BODY_SIZE
反例: MAX_SIZE,MAX_REQUEST_SIZE
注意:定义常量同时加上final static - Rule 7. 【强制】如果使用到了通用的设计模式,在类名中体现,有利于阅读者快速理解设计思想
正例:OrderFactory, LoginProxy ,ResourceObserver - Rule 8. 【强制】枚举类名以Enum结尾
抽象类使用Abstract开头
异常类使用Exception结尾
测试类以它要测试的类名开始,以Test结尾
正例:DealStatusEnum, AbstractView,BaseView, TimeoutException,UserServiceTest - Rule 10. 【强制】Bean、entity、VO类中布尔类型的变量名,不要加is前缀,否则部分框架解析会引起序列化错误
- Rule 11. 【强制】服务间传输实体结尾为Bean、页面接口实体结尾为VO、数据库实体在entity包下,使用代码自动什么工具生成
- Rule 12. 【推荐】定义常量代替魔法数字,便于理解业务含义
反例:
if (status == 1) {
...
}
正例:
if (status == FAILED) {
...
}
3. 格式规约
- Rule 1. 【强制】使用基于IDE自动的代码格式化,勾选提交时自动格式化
- Rule 2. 【强制】IDE的file encoding设置为UTF-8; 换行符使用Unix格式,不要使用Windows格式
- Rule 3. 【推荐】通过空行进行逻辑分段,注释前面空一行
//获取本机IP和端口
InetSocketAddress localAddress = (InetSocketAddress) ctx.channel().localAddress();
this.localAddr = localAddress.getAddress().getHostAddress();
this.localPort = localAddress.getPort();
//读取Http Method
this.httpMethod = fullHttpRequest.method().toString();
- Rule 4. 【强制】所有类加上注释 ,并带上日期和作者,代码自动生成
4. 注释规约
- Rule 1. 【推荐】通过更清晰的代码来避免注释
正例:
List<Host> hostCopyForLoadbalancerSelect=new ArrayList(hostList);
反例:
//复制一份主机列表,负载均衡筛选时使用
List<Host> newHostList=new ArrayList(hostList); - Rule 2. 【推荐】删除无意义注释
- Rule 3. 【强制】代码修改的同时,注释也要进行相应的修改。尤其是参数、返回值、异常、核心逻辑等的修改
- Rule 4. 【推荐】如果大概率不再使用,直接删除代码,而不是大片注释代码
- Rule 5. 【强制】类、类的公有成员、方法的注释必须使用Javadoc规范使用/ xxx /格式,不得使用//xxx方式*
- **Rule 6. 【推荐】注释不要为了英文而英文
- Rule 7. 【强制】TODO标记,清晰说明待办事项
5. 方法设计
- Rule 1. 【推荐】方法代码行数尽量小于100行****
- Rule 2. 【推荐】方法的语句在同一个抽象层级上
反例:一个方法里,前20行代码在进行很复杂的基本价格计算,然后调用一个折扣计算函数,再调用一个赠品计算函数
正例:此时可将前20行也封装成一个价格计算函数,使整个方法在同一抽象层级上。 - Rule 3. 【推荐】尽量减少重复的代码,建议使用Intellij IDEA旗舰版
- Rule 4. 【推荐】方法参数不要过多(不超过5个),可以传递对象、拆分多个方法来减少参数数量
- Rule 5. 【推荐】方法参数进行校验,尤其是对外提供的方法。
- Rule 6. 【推荐】下列情形,不需要进行参数校验
约定俗成由更上层校验的参数
会被循环调用的方法
private方法,且明确知道调用处代码做了参数检查 - Rule 7.【推荐】 非必要对外公开,声明为private,减少以调用方的负担
- Rule 8.【推荐】对象返回值可以Null,集合尽量返回空集合
- Rule 9.【强制】正被外部调用的方法,不允许修改方法参数,避免对接口的调用方产生影响
正例:新增新方法,并对已过时方法加@Deprecated注解,并在Deprecated处说明新方法是什么 - Rule 10.【推荐】不使用@Deprecated的类或方法
- Rule 11.【推荐】不使用不稳定方法,如com.sun.*包下的类,底层类库中internal包下的类
6. 控制语句
- Rule 1.【推荐】少用if-else方式,减少嵌套层次
正例: - Rule 2.【强制】if, else, for, do, while语句必须使用大括号,即使只有单条语句
- Rule 3.【推荐】将复杂逻辑判断的结果赋值给布尔变量,以提高可读性
正例:boolean existed = (file.open(fileName, "w") != null) && (...) || (...); - Rule 4.【推荐】善用三元运算符,减少if-else语句的编写
正例:s != null ? s : ""; - Rule 5.【推荐】减少使用取反的逻辑,容易写错
反例:
if(!StringUtils.isEmpty(str)){ … }
正例:
if(StringUtils.isNotEmpty(str)){…} - Rule 6.【推荐】表达式中,短路概率较大的条件尽量放前面,使得后面的判断可以免于执行
- Rule 7.【推荐】避免死循环,尤其递归调用
- Rule 8.【强制】字符if else比较,使用switch替代
反例: - 正例:
7. 类设计
- Rule 1. 【推荐】类成员与方法的可见性最小化
尽量减少public方法的数量,如果需要单元测试,可以适当扩大到package范围 - Rule 2. 【推荐】高类聚,低耦合
- Rule 3. 【推荐】定义变量与方法参数时,尽量使用接口而不是具体类
- Rule 4. 【强制】所有的子类覆写方法,必须加@Override注解
- Rule 5. 【强制】静态方法不能被子类覆写
- Rule 6. 【强制】Object的equals方法容易抛空指针异常,应使用常量或确定非空的对象来调用equals
正例:
“test”.equals(object);
Objects.equals(object, "test"); - Rule 7. 【强制】线程内共享资源对象ThreadLocal的定义,必须声明为static
- Rule 8. 【推荐】使用lombok生成getter&setter,避免大量重复代码
- Rule 9. 【强制】serializable的POJO类,继承关系中不能有属性覆盖,hessian反序列化时会丢失字段
反例:
8. 基本类型
- Rule 1.【强制】需要表达“空、无”含义时,使用包装类型
正例:允许为空的方法参数、Bean,VO和entity类属性,如:Long/Integer - Rule 2. 【强制】需要序列化的Bean,VO类属性使用包装数据类型
- Rule 3. 【强制】RPC方法的返回值和参数使用包装数据类型
- Rule 4. 【推荐】调用者与被调用函数间尽量使用同一类型,减少默认转换
正例:Integer i = Integer.valueOf(str); - Rule 5. 【强制】 所有包装类对象之间值的比较,全部使用equals方法比较
- Rule 6. 【强制】 BigDecimal需要使用compareTo()
- Rule 7. 【强制】 Atomic 系列,不能使用equals方法*
- Rule 8. 【强制】 Double、Float类型计算时会丢失精度,金额等转换为整数后计算或者使用BigDecimal
反例:float f = 0.45f/3; //结果是0.14999999
正例:货币金额以“分”为单位计算,或者使用BigDecimal - Rule 9. 【强制】数字运算表达式,等式两边的类型要一致
- Rule 10. 【强制】考虑类型计算结果溢出的情况
- Rule 11. 【强制】负数取模还是负数,取模结果用作数组索引时取绝对值
- Rule 12. 【推荐】拼接使用StringBuilder的append()方法,new StringBuilder(size)尽量指定size大小
- Rule 13. 【推荐】如果字符串长度很大且频繁拼接,可考虑ThreadLocal重用StringBuilder对象
- Rule 14. 【推荐】字符操作时,优先使用字符参数,而不是字符串,能提升性能
9. 集合处理
- Rule 1. 【推荐】底层数据结构是数组的集合,指定集合初始大小
如:ArrayList(默认10),HashMap(默认16),HashSet等,HashMap和HashSet还需要考虑加载因子 - Rule 2. 【推荐】尽量使用新式的foreach语法遍历Collection与数组
- Rule 3. 【强制】不要在foreach循环里进行元素的remove/add操作,remove元素使用Iterator方式
- Rule 4. 【强制】使用entrySet遍历Map,而不是keySet 方式进行遍历
- Rule 5. 【强制】当对象用于集合时,需要重写对象的hashCode()和 equals()方法
- Rule 6. 【强制】注意各种Map集合Key/Value是否允许为空
- Rule 7. 【强制】集合如果存在并发修改的场景,需要使用线程安全的版本
正例: ConcurrentHashMap 、CopyOnWriteArrayList、 Collections.synchronizedList(list) - Rule 8. 【强制】 ConcurrentHashMap使用putIfAbsent方法,否则会出现多线程互相覆盖
- Rule 9. 【推荐】如果Key只有有限的可选值,先将Key封装成Enum,并使用EnumMap
- Rule 12. 【推荐】Array 与 List互转的正确写法
String[] array = list.toArray(new String[0]);
//list不能再扩展;
List list = Arrays.asList(array)
//list可扩展
List list = new ArrayList(array.length); Collections.addAll(list, array);
10. 并发处理
- Rule 1. 【强制】创建线程或线程池时必须指定有意义的线程名称
正例:
Thread t = new Thread();
t.setName("cleanup-thread"); - Rule 2. 【强制】不允许使用 Executors去创建线程池
正例: new ThreadPoolExecutor(xxx,xxx,xxx,xxx)
明确指定如下参数:
线程数
队列大小
拒绝策略
线程名称
UncaughtExceptionHanlder - Rule 3. 【强制】正确停止线程池,先执行shutdown(),再执行shutdownNow()
oExecutorService.shutdown(): 不允许提交新任务,等待当前任务及队列中的任务全部执行完毕后退出
oExecutorService.shutdownNow(): 通过Thread.interrupt()试图停止所有正在执行的线程,并不再处理还在队列中等待的任务 - Rule 4. 【强制】Runnable中必须捕获一切异常
oScheduledExecutorService:任务会被中断,该任务将不再定时调度
oExecutorService:当前线程会中断,线程池需要创建新的线程来响应后续任务 - Rule 5. 【强制】全局的非线程安全的对象可考虑使用ThreadLocal存放
正例:SimpleDateFormat,MD5/SHA1的Digest - Rule 6. 【推荐】能锁区块,就不要锁整个方法,能用对象锁,就不要用类锁
- Rule 7. 【推荐】读写分离锁ReentrantReadWriteLock
- Rule 8. 【推荐】分段锁, 如JDK7的ConcurrentHashMap
正例:写多读少的计数器,分散多个Counter,取值时再累加所有Counter - Rule 9. 【推荐】无锁数据结构,如JDK8的ConcurrentHashMap,AtomicXXX, ThreadLocalRandom
- Rule 10. 【推荐】使用volatile修饰符,修改所有线程可见
11. 异常处理
-
Rule 1. 【强制】
每个业务实现异常码,放到各个业务服务的api包中,包名:com.oppo.ipd.xxx.constant,参考FileExceptionCode.java;
通用异常使用ErrorCode,业务提示异常严禁使用ErrorCode;
所有异常必须转换成IpdException异常,转换前必须打印异常,且不能丢弃堆栈,具体参考Rule5;
抛出异常使用方法: throw new IpdException(FileExceptionCode.BUSINESS_CODE_EMPTY,"业务编码为空");
所有方法上不要显式抛出异常 -
Rule 2. 【强制】创建异常的消耗大,不要用来做流程控制,条件控制
-
Rule 3. 【强制】发生概率较高的条件,应该先进行检查规避
正例:IndexOutOfBoundsException,NullPointerException等 -
Rule 4. 【推荐】如果异常的message不变,将异常定义为静态成员变量
-
Rule 5. 【推荐】异常日志应包含排查问题的足够信息,堆栈不能丢弃
正例: -
-
Rule 6. 【推荐】尽量使用JDK标准异常
正例: IllegalArgumentException,IllegalStateException,UnsupportedOperationException -
Rule 7. 【推荐】多个异常的处理逻辑一致时,使用JDK7的语法避免重复代码
正例: -
-
Rule 8. 【强制】捕获异常一定要处理;如果故意捕获并忽略异常,须要注释写明原因
-
Rule 9. 【强制】异常处理不能吞掉原异常,要么在日志打印,要么在重新抛出的异常里包含原异常
-
Rule 10. 【强制】如果不想处理异常,可以不进行捕获,但最外层的业务使用者,必须处理异常,将其转化为用户可以理解的内容
-
Rule 11. 【强制】必须对资源对象、流对象进行关闭,或使用语法try-with-resource
-
Rule 12. 【强制】不能在finally块中使用return
-
Rule 13. 【强制】不能在finally块中抛出异常
- 日志规约
- Rule 1. 【强制】应用中不可直接使用日志库(Log4j、Logback)中的API,而应使用日志框架SLF4J中的API
正例: private static Logger logger = LoggerFactory.getLogger(Foo.class); - Rule 2. 【强制】对不确定会否输出的日志,先条件判断;如果使用占位符的方式,可以不必判断
- Rule 3. 【推荐】频繁输出的日志直接拼接字符串,不频繁的使用占位符,直接拼接字符串的执行效率,比使用占位符高得多
- Rule 4. 【推荐】尽量使用异步日志, 注意正确配置异步队列长度及队列满时如何处理
- Rule 5. 【强制】禁止使用性能很低的System.out、 e.printStackTrace()打印信息
- Rule 7. 【推荐】谨慎地记录日志,避免大量输出无效日志,信息不全的日志
- Rule 8. 【推荐】使用warn级别而不是error级别,记录外部输入参数错误的情况
- Rule 9. 【强制】日志文件设置按文件大小进行滚动,并限制文件数量,避免磁盘被日志打满的情况
- Rule 10. 【推荐】日志文件名设置为.gz结尾,滚动时日志框架会自动进行压缩
- Rule 11. 【推荐】避免同一个part的日志%i滚动过多,难以找到最新的日志文件
- 其他设计
- Rule 1. 【推荐】使用System.currentTimeMillis()获取当前毫秒数,new Date().getTime()性能差很多
- Rule 2. 【推荐】使用System.nanoTime()获得机器从启动到现在流逝的纳秒数(不受NTP调整影响)
- Rule 3. 【推荐】变量声明尽量靠近使用的地方
- Rule 4. 【推荐】不要像C那样一行里做多件事情
- Rule 5. 【推荐】不要为了性能而使用JNI(JIT性能足够好),为了减少GC可以使用JNI
- Rule 6. 【推荐】正确使用反射,减少性能损耗
正例:获取Method/Field对象的性能消耗较大, 而如果对Method与Field对象进行缓存 - Rule 7. 【推荐】工具类,定义private构造函数使其不能被实例化
- Rule 8. 【推荐】提测发布的包注明版本号,便于排查和追溯问题
反例:一直使用1.0.0-SNAPSHOT - Rule 9. 【强制】相同版本的包不要修改后deploy多次,避免被其他服务引用到错误的包,无法排查追溯
-