阿⾥开发规范(精简版)
Java开发规范
命名
【规范】类名使⽤ UpperCamelCase 风格,必须遵从驼峰形式,但以下情形例外: ( 领域模型的相关命名 )DO / BO / DTO / VO 等。
正例: MarcoPolo / UserDO / XmlService / TcpUdpDeal / TaPromotion
反例: macroPolo / UserDo / XMLService / TCPUDPDeal / TAPromotion
【规范】⽅法名、参数名、成员变量、局部变量都统⼀使⽤ lowerCamelCase 风格,必须遵从驼峰形式。
正例: localValue / getHttpMessage() / inputUserId
【规范】 常量命名全部⼤写,单词间⽤下划线隔开,⼒求语义表达完整清楚,不要嫌名字长。
【规范】抽象类命名使⽤ Abstract 或 Base 开头 ; 异常类命名使⽤ Exception 结尾 ; 测试类命名以它
要测试的类的名称开始,以 Test 结尾。枚举类名建议带上 Enum 后缀,枚举成员名称需要全⼤写,单词间⽤下划线隔开。
【规范】POJO 类中布尔类型的变量,都不要加 is ,否则部分框架解析会引起序列化错误。
【规范】各层命名规约:
A) Service / DAO 层⽅法命名规约
1 ) 获取单个对象的⽅法⽤ get 做前缀。
2 ) 获取多个对象的⽅法⽤ list 做前缀(习惯:getXXXList)。
3 ) 获取统计值的⽅法⽤ count 做前缀。
4 ) 插⼊的⽅法⽤ save( 推荐 ) 或 insert 做前缀。
5 ) 删除的⽅法⽤ remove( 推荐 ) 或 delete 做前缀。
6 ) 修改的⽅法⽤ update 做前缀(或modify)。
B) 领域模型命名规约
1 ) 数据对象: xxxDO , xxx 即为数据表名。
2 ) 数据传输对象: xxxDTO , xxx 为业务领域相关的名称。
3 ) 展⽰对象: xxxVO , xxx ⼀般为⽹页名称。
4 ) POJO 是 DO / DTO / BO / VO 的统称,禁⽌命名成 xxxPOJO 。
常量
【规范】 不允许任何魔法值( 即未经定义的常量 ) 直接出现在代码中。
反例: String key =” Id # taobao _”+ tradeId;
cache . put(key , value);
格式规约
【风格】单⾏太长需换⾏
【风格】⽅法体内的执⾏语句组、变量的定义语句组、不同的业务逻辑之间或者不同的语义之间插⼊⼀个空⾏。相同业务逻辑和语义之间不需要插⼊空⾏。
OOP规约
【效率】避免通过⼀个类的对象引⽤访问此类的静态变量或静态⽅法,⽆谓增加编译器解析成本,直接⽤类名来访问即可。
【规范】所有的覆写⽅法,必须加@ Override 注解。
【规范】对外暴露的接⼝签名, 原则上不允许修改⽅法签名,避免对接⼝调⽤⽅产⽣影响。 接⼝过时必须加@Deprecated 注解,并清晰
地说明采⽤的新接⼝或者新服务是什么。
【规范】Object 的 equals ⽅法容易抛空指针异常, 应使⽤常量或确定有值的对象来调⽤equals。
正例: ” test ” .equals(object);
反例: object.equals( ” test ” );
【规范】 所有的相同类型的包装类对象之间值的⽐较,全部使⽤ equals ⽅法⽐较。( 注意空指针)
说明:对于 Integer var =?在-128 ⾄ 127 之间的赋值, Integer 对象是在IntegerCache . cache 产⽣,
会复⽤已有对象,这个区间内的Integer 值可以直接使⽤==进⾏判断,但是这个区间之外的所有数据,都会在堆上产⽣,并不会复⽤已有对象,这是⼀个⼤坑,推荐使⽤equals ⽅法进⾏判断。
【规范】关于基本数据类型与包装数据类型的使⽤标准如下:
1 ) 所有的 POJO 类属性必须使⽤包装数据类型。
2 ) RPC ⽅法的返回值和参数必须使⽤包装数据类型。
3 ) 所有的局部变量【推荐】使⽤基本数据类型。
【强制】序列化类新增属性时,请不要修改 serialVersionUID 字段,避免反序列失败 ; 如果完全不兼容升级,避免反序列化混乱,那么请修改 serialVersionUID 值。
【规范】构造⽅法⾥⾯禁⽌加⼊任何业务逻辑,如果有初始化逻辑,请放在 init ⽅法中。
【规范】使⽤索引访问⽤ String 的 split ⽅法得到的数组时,需做最后⼀个分隔符后有⽆内容的检查,否则会有抛IndexOutOfBoundsException 的风险。
说明:
String str = “a,b,c,,”;
String[] ary = str.split(“,”);
//预期⼤于 3,结果是 3
System.out.println(ary.length);
【规范】当⼀个类有多个构造⽅法,或者多个同名⽅法,这些⽅法应该按顺序放置在⼀起,便于阅读。
【风格】类内⽅法定义顺序依次是:公有⽅法或保护⽅法 > 私有⽅法 > getter / setter⽅法。
【效率】final 可提⾼程序响应效率,声明成 final 的情况:
1 ) 不需要重新赋值的变量,包括类属性、局部变量。
2 ) 对象参数前加 final ,表⽰不允许修改引⽤的指向。
3 ) 类⽅法确定不允许被重写。
4 )例⼦:final boolean existed = (file.open(fileName, “w”) != null) && (…) || (…);
集合处理
【强制】 关于 hashCode 和 equals 的处理,遵循如下规则:
1) 只要重写 equals ,就必须重写 hashCode 。
2) 因为 Set 存储的是不重复的对象,依据 hashCode 和 equals 进⾏判断,所以 Set 存储的对象必须重写这两个⽅法。
3) 如果⾃定义对象做为 Map 的键,那么必须重写 hashCode 和 equals 。
【强制】不要在 foreach 循环⾥进⾏元素的 remove / add 操作。 remove 元素请使⽤ Iterator⽅式,如果并发操作,需要对 Iterator 对象加锁。
反例:
List<String> a = new ArrayList<String>();
a.add(“1”);
a.add(“2”);
for (String temp : a) {
if(“1”.equals(temp)){
}
}
说明:以上代码的执⾏结果肯定会出乎⼤家的意料,那么试⼀下把“1”换成“2”,会是同样的结果吗?
(java.util.ConcurrentModificationException)
正例:
Iterator<String> it = a.iterator();
while(it.hasNext()){
String temp = it.next();
if(删除元素的条件){
}
}
【规范】集合初始化时,尽量指定集合初始值⼤⼩。
说明: ArrayList 尽量使⽤ ArrayList(int initialCapacity) 初始化。
【规范】使⽤ entrySet 遍历 Map 类集合 KV,⽽不是 keySet ⽅式进⾏遍历。
说明: keySet 其实是遍历了 2 次,⼀次是转为 Iterator 对象,另⼀次是从 hashMap 中取出 key 所对应的 value。⽽ entrySet 只是遍历了⼀次就把 key 和 value 都放到了 entry 中,效 率更⾼。 如果是 JDK8,使⽤ Map.foreach ⽅法。
Map<String, String> map = new HashMap<String, String>();
map.put(“1”, “@@”);
map.put(“2”, “##”);
/**
* JDK8推荐使⽤
*/
map.forEach((K, V) -> {
System.out.println(“Key : ” + K);
System.out.println(“Value : ” + V);
});
/**
* foreach推荐使⽤
*/
for (Map.Entry<String, String> entry : Set()) {
System.out.println(“Key : ” + Key());
System.out.println(“Value : ” + Value());
}
/**
* 不推荐使⽤
*/
for (String key : map.keySet()) {
System.out.println(“Key : ” + key);
System.out.println(“Value : ” + (key));
}
【强制】⾼度注意 Map 类集合 K/V 能不能存储 null 值的情况,如下表格:
集合类Key Value Super说明Hashtable不允许为 null不允许为 null Dictionary线程安全ConcurrentHashMap不允许为 null不允许为 null AbstractMap分段锁技术TreeMap不允许为 null允许为 null AbstractMap线程不安全
HashMap允许为 null允许为 null AbstractMap线程不安全
并发处理
【规范】获取单例对象需要保证线程安全,其中的⽅法也要保证线程安全。
说明:资源驱动类、⼯具类、单例⼯⼚类都需要注意。
【规范】创建线程或线程池时请指定有意义的线程名称,⽅便出错时回溯。
正例:
public class TimerTaskThread extends Thread { public TimerTaskThread(){
super.setName(“TimerTaskThread”); … }
【规范】线程资源必须通过线程池提供,不允许在应⽤中⾃⾏显式创建线程。
说明:使⽤线程池的好处是减少在创建和销毁线程上所花的时间以及系统资源的开销,解决资 源不⾜的问题。如果不使⽤线程池,有可能造成系统创建⼤量同类线程⽽导致消耗完内存或者 “过度切换”的问题。
抽象类的使用【规范】 线程池不允许使⽤ Executors 去创建,⽽是通过 ThreadPoolExecutor 的⽅式, 这样 的处理⽅式让写的同学更加明确线程池的运⾏规则, 规避资源耗尽的风险。 说明:Executors 返回的线程池对象的弊端如下:
1)FixedThreadPool 和 SingleThreadPool:
允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积⼤量的请求,从⽽导致 OOM。
2)CachedThreadPool 和 ScheduledThreadPool:
允许的创建线程数量为 Integer.MAX_VALUE,可能会创建⼤量的线程,从⽽导致 OOM。
【效率】⾼并发时, 同步调⽤应该去考量锁的性能损耗。能⽤⽆锁数据结构,就不要⽤锁;能 锁区块,就不要锁整个⽅法体;能⽤对象锁,就不要⽤类锁。
【强制】对多个资源、数据库表、对象同时加锁时, 需要保持⼀致的加锁顺序,否则可能会造 成死锁。
说明:线程⼀需要对表 A、B、C 依次全部加锁后才可以进⾏更新操作,那么线程⼆的加锁顺序 也必须是 A、B、C,否则可能出现死锁。
【规范】并发修改同⼀记录时,避免更新丢失,要么在应⽤层加锁,要么在缓存加锁,要么在 数据库层使⽤乐观锁,使⽤ version 作为更新依据。
说明:如果每次访问冲突概率⼩于 20%,推荐使⽤乐观锁,否则使⽤悲观锁。乐观锁的重试次 数不得⼩于 3 次。
【规范】多线程并⾏处理定时任务时, Timer 运⾏多个 TimeTask 时,只要其中之⼀没有捕获 抛出的异常,其它任务便会⾃动终⽌运⾏,使⽤ ScheduledExecutorService 则没有这个问题。
【规范】HashMap 在容量不够进⾏ resize 时由于⾼并发可能出现死链,导致 CPU 飙升,在 开发过程中注意规避此风险。
控制语句
【规范】在⼀个 switch 块内,每个 case 要么通过 break/return 等来终⽌,要么注释说明程 序将继续执⾏到哪⼀个 case 为⽌;在⼀个switch 块内, 都必须包含⼀个 default 语句并且 放在最后,即使它什么代码也没有。
【规范】在 if/else/for/while/do 语句中 必须使⽤⼤括号,即使只有⼀⾏代码,避免使⽤ 下⾯的形式:if (condition) statements;
【规范】推荐尽量少⽤ else, if-else 的⽅式可以改写成:
if(condition){
…
return obj; }
// 接着写 else 的业务逻辑代码;
说明:如果⾮得使⽤if()…else if()…else…⽅式表达逻辑,【强制】请勿超过3层,
超过请使⽤状态设计模式 或者 卫语句。
卫语句⽰例:
【规范】除常⽤⽅法(如 getXxx/isXxx)等外,不要在条件判断中执⾏其它复杂的语句,将复 杂逻辑判断的结果赋值给⼀个有意义的布尔变量名,以提⾼可读性。
说明:很多 if 语句内的逻辑相当复杂,阅读者需要分析条件表达式的最终结果,才能明确什么 样的条件执⾏什么样的语句,那么,如果阅读者分析逻辑表达式错误呢?正例://伪代码如下
boolean existed = (file.open(fileName, “w”) != null) && (…) || (…); if (existed) {… }反例:
if ((file.open(fileName, “w”) != null) && (…) || (…)) { …}
【规范】⽅法中需要进⾏ 参数校验的场景:1) 调⽤频次低的⽅法。
2) 执⾏时间开销很⼤的⽅法,参数校验时间⼏乎可以忽略不计,但如果因为参数错误导致中间执⾏回退,或者错误,那得不偿失。3) 需要极⾼稳定性和可⽤性的⽅法。
4) 对外提供的开放接⼝,不管是RPC/API/HTTP接⼝。5) 敏感权限⼊⼝。
【规范】⽅法中 不需要参数校验的场景:
1) 极有可能被 循环调⽤的⽅法,不建议对参数进⾏校验。但在⽅法说明⾥必须注明外部参数检查。
2) 底层的⽅法调⽤频度都⽐较⾼,⼀般不校验。毕竟是像纯净⽔过滤的最后⼀道,参数错误不太可能到底层才会暴露问题。⼀般 DAO 层与 Service 层都在同⼀个应⽤中,部署在同⼀ 台服务器中,所以 DAO 的参数校验,可以省略。
[java]
1. public void today() { if (isBusy()) {
2. System.out.println(“change time.”); return;
3. }
4. if (isFree()) {
5. System.out.println(“go to travel.”);
6. return;
7. }
8. System.out.println(“stay at home to learn Alibaba Java Coding Guidelines.”); 9. return; 10. }
public void today() { if (isBusy()) {
System.out.println(“change time.”); return;}
if (isFree()) {
System.out.println(“go to travel.”);return; }
System.out.println(“stay at home to learn Alibaba Java Coding Guidelines.”);return; }
123456789
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论