JAVA开发规范

 

 

1  方法行数不能超过50行,特殊情况除外;说明:如果行数过长不利于整个方法的阅读理解。如果是笔记本建议控制在40以内。

2  方法参数不能多于7个,特殊情况除外;说明:参数过多不利于整个方法的阅读理解。

3  变量名称需有意义且符合驼峰式写法,严禁出现a,b,c 等字符作为变量名称。

4  严禁出现魔鬼数字(在代码中没有具体含义的数字、字符串)。

5  新建类名,方法名意义尽量切近当前功能模块的功能,且符合驼峰式写法。

6  If语句后必须写花括号,严禁出现 if(true)后面直接写代码,需带花括号{}。

7  条件判断中必须有空格 如 if (1  ==  2)。 等号两边需加空格。

8  严禁使用==判断字符串值,需使用equals方法判断。

9  与null对象进行判断, 需写成(null  ==  xxx) 形式,null写在前;说明:有时候如果将变量写在前,恰好将==疏忽写成= 就会造成 xxx = null,等于是给变量赋值为null。

10 对当前对象进行null判断,并且进行调用对象方法判断时,形如if(null !=  xxx  && xxx.size()  >  0)需将null !=  xxx判断写在前,这样如果为null,可以直接短路,防止空指针异常产生。

11 静态常量名称应大写,多个单词可用下划线拼接,如 SELECT_NUMBER = 1。

12 方法注释,若当前方法功能较为复杂,需以javadoc方式注释进行说明,注释需写成形如

/**

     *

     * @author username

     * @param oldStage

  */

13  无需再对boolean 值再进行判断,直接使用即可,如 if (success) { TODO…}。

    反例: if (success == true) { TODO…}

14  POJO 类中的任何布尔类型的变量,都不要加 is,否则部分框架解析会引起序列化错误。反例:定义为基本数据类型 boolean isSuccess;的属性,它的方法也是 isSuccess(),RPC框架在反向解析的时候,“以为”对应的属性名称是 success,导致属性获取不到,进而抛出异常。

15  if/for/while/switch/do 等保留字与左右括号之间都必须加空格。任何运算符左右必须加一个空格。说明:运算符包括赋值运算符=、逻辑运算符&&、加减乘除符号、三目运行符等。

16  IDE 的 text file encoding 设置为 UTF-8。

17  Object的equals方法容易抛空指针异常,应使用常量或确定有值的对象来调用equals。

例如: "test".equals(object)

18  POJO 类必须写 toString 方法。使用工具类 source> generate toString 时,如果继

承了另一个 POJO 类,注意在前面加一下 super.toString。说明:在方法执行抛出异常时,可以直接调用 POJO 的 toString()方法打印其属性值,便于排查问题。

19  使用索引访问用 String 的 split 方法得到的数组时,需做最后一个分隔符后有无内

容的检查,否则会有抛 IndexOutOfBoundsException 的风险。说明:

String str = "a,b,c,,"; String[] ary = str.split(",");

//预期大于 3,结果是 3

System.out.println(ary.length);

20  【推荐】当一个类有多个构造方法,或者多个同名方法,这些方法应该按顺序放置在一起,便于阅读。

21  【推荐】 类内方法定义顺序依次是:公有方法或保护方法 > 私有方法 > getter/setter

方法。

22 【推荐】setter 方法中,参数名称与类成员变量名称一致,this.成员名=参数名。在

getter/setter 方法中,尽量不要增加业务逻辑,增加排查问题难度。

反例:

public Integer getData(){

if(true) {

return data + 100;

} else {

return data - 100;

}

}

23  【推荐】循环体内,字符串的联接方式,使用 StringBuilder 的 append 方法进行扩展。

反例:

String str = "start";

for(int i=0; i<100; i++){

str = str + "hello";

}

说明:反编译出的字节码文件显示每次循环都会 new 出一个 StringBuilder 对象,然后进行append 操作,最后通过 toString 方法返回 String 对象,造成内存资源浪费。

24  【推荐】final 可提高程序响应效率,声明成 final 的情况:

1) 不需要重新赋值的变量,包括类属性、局部变量。

2) 对象参数前加 final,表示不允许修改引用的指向。

3) 类方法确定不允许被重写。

25  Map/Set 的 key 为自定义对象时,必须重写 hashCode 和 equals。正例:String 重写hashCode 和 equals 方法,所以我们可以非常愉快地使用 String 对象作为 key 来使用。

26  使用集合转数组的方法,必须使用集合的 toArray(T[] array),传入的是类型完全

一样的数组,大小就是 list.size()。

反例:直接使用 toArray 无参方法存在问题,此方法返回值只能是 Object[]类,若强转其它类型数组将出现 ClassCastException 错误。

正例:

List list = new ArrayList(2);

list.add("jun");

list.add("jiang");

String[] array = new String[list.size()];

array = list.toArray(array);

说明:使用 toArray 带参方法,入参分配的数组空间不够大时,toArray 方法内部将重新分配内存空间,并返回新数组地址;如果数组元素大于实际所需,下标为[ list.size() ]的数组元素将被置为 null,其它数组元素保持原值,因此最好将方法入参数组大小定义与集合元素个数一致

27  不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用 Iterator

方式,如果并发操作,需要对 Iterator 对象加锁。

反例:

List a = new ArrayList();

a.add("1");

a.add("2");

for (String temp : a) {

if("1".equals(temp)){

a.remove(temp);

}

}

说明:这个例子的执行结果会出乎大家的意料,那么试一下把“1”换成“2”,会是同样的结果吗?

正例:

Iterator it = a.iterator();

while(it.hasNext()){

String temp = it.next();

if(删除元素的条件){

it.remove();

}

}

28  【推荐】集合初始化时,尽量指定集合初始值大小。说明:ArrayList 尽量使用 ArrayList(int initialCapacity) 初始化。

29  【推荐】使用 entrySet 遍历 Map 类集合 KV,而不是 keySet 方式进行遍历。

说明:keySet 其实是遍历了 2 次,一次是转为 Iterator 对象,另一次是从 hashMap 中取出 key所对应的 value。而 entrySet 只是遍历了一次就把 key 和 value 都放到了 entry 中,效率更高。如果是 JDK8,使用 Map.foreach 方法。

正例:values()返回的是 V 值集合,是一个 list 集合对象;keySet()返回的是 K 值集合,是一个 Set 集合对象;entrySet()返回的是 K-V 值组合集合。

30  SimpleDateFormat 是线程不安全的类,一般不要定义为 static 变量,如果定义为static,必须加锁,或者使用 DateUtils 工具类。

正例:注意线程安全,使用 DateUtils。亦推荐如下处理:

private static final ThreadLocal df = new ThreadLocal() {

@Override

protected DateFormat initialValue() {

return new SimpleDateFormat("yyyy-MM-dd");

}

};

说明:如果是 JDK8 的应用,可以使用 instant 代替 Date,Localdatetime 代替 Calendar,

Datetimeformatter 代替 Simpledateformatter,官方给出的解释:simple beautiful strong

immutable thread-safe。

31  高并发时,同步调用应该去考量锁的性能损耗。能用无锁数据结构,就不要用锁;能

锁区块,就不要锁整个方法体;能用对象锁,就不要用类锁。

32  多线程并行处理定时任务时,Timer 运行多个 TimeTask 时,只要其中之一没有捕获

抛出的异常,其它任务便会自动终止运行,使用 ScheduledExecutorService 则没有这个问题。

33  创建线程或线程池时请指定有意义的线程名称,方便出错时回溯。

34  在一个 switch 块内,每个 case 要么通过 break/return 来终止,要么注释说明程序

将继续执行到哪一个 case 为止;在一个 switch 块内,都必须包含一个 default 语句并且放在最后,即使它什么代码也没有。

35  循环体中的语句要考量性能,以下操作尽量移至循环体外处理,如定义对象、变量、获取数据库连接,进行不必要的 try-catch 操作(这个 try-catch 是否可以移至循环体外)。

36  所有的抽象方法(包括接口中的方法)必须要用 javadoc 注释、除了返回值、参数、

异常说明外,还必须指出该方法做什么事情,实现什么功能。

说明:如有实现和调用注意事项,请一并说明。

37  所有的类都必须添加创建者信息。

38  所有的枚举类型字段必须要有注释,说明每个数据项的用途。

39  代码修改的同时,注释也要进行相应的修改,尤其是参数、返回值、异常、核心逻辑等的修改。

    说明:代码与注释更新不同步,就像路网与导航软件更新不同步一样,如果导航软件严重滞后,就失去了导航的意义。 

40  【参考】注释掉的代码尽量要配合说明,而不是简单的注释掉。

说明:代码被注释掉有两种可能性:1)后续会恢复此段代码逻辑。2)永久不用。前者如果没有备注信息,难以知晓注释动机。后者建议直接删掉(代码仓库保存了历史代码)。

41  【参考】对于注释的要求:第一、能够准确反应设计思想和代码逻辑;第二、能够描述业务含义,使别的程序员能够迅速了解到代码背后的信息。完全没有注释的大段代码对于阅读者形同天书,注释是给自己看的,即使隔很长时间,也能清晰理解当时的思路;注释也是给继任者看的,使其能够快速接替自己的工作。

42  错误,不能工作(FIXME):(标记人,标记时间,[预计处理时间])在注释中用 FIXME 标记某代码是错误的,而且不能工作,需要及时纠正的情况。

43  在使用正则表达式时,利用好其预编译功能,可以有效加快正则匹配速度。

说明:不要在方法体内定义:Pattern pattern = Pattern.compile(规则);

44  注意 Math.random() 这个方法返回是 double 类型,注意取值范围 0≤x<1(能够取到零值,注意除零异常),如果想获取整数类型的随机数,不要将 x 放大 10 的若干倍然后取整,直接使用 Random 对象的 nextInt 或者 nextLong 方法。

45  获取当前毫秒数:System.currentTimeMillis(); 而不是 new Date().getTime();

说明:如果想获取更加精确的纳秒级时间值,用 System.nanoTime。在 JDK8 中,针对统计时间等场景,推荐使用 Instant 类。

46  【推荐】任何数据结构的使用都应限制大小。说明:这点很难完全做到,但很多次的故障都是因为数据结构自增长,结果造成内存被吃光。

47  【推荐】对于“明确停止使用的代码和配置”,如方法、变量、类、配置文件、动态配置属性等要坚决从程序中清理出去,避免造成过多垃圾。清理这类垃圾代码是技术气场,不要有这样的观念:“不做不错,多做多错”。

48  不要捕获 Java 类库中定义的继承自 RuntimeException 的运行时异常类,如:

IndexOutOfBoundsException / NullPointerException,这类异常由程序员预检查来规避,保证程序健壮性。

正例: if(obj != null) {...}

反例: try { obj.method() } catch(NullPointerException e){…}

49  异常不要用来做流程控制,条件控制,因为异常的处理效率比条件分支低。

50  finally 块必须对资源对象、流对象进行关闭,有异常也要做 try-catch。

说明:如果 JDK7,可以使用 try-with-resources 方法。

51  不能在 finally 块中使用 return,finally 块中的 return 返回后方法结束执行,不

会再执行 try 块中的 return 语句。

52  避免出现重复的代码(Don’t Repeat Yourself),即 DRY 原则。

说明:随意复制和粘贴代码,必然会导致代码的重复,在以后需要修改时,需要修改所有的副本,容易遗漏。必要时抽取共性方法,或者抽象公共类,甚至是共用模块。

正例:一个类中有多个 public 方法,都需要进行数行相同的参数校验操作,这个时候请抽取:

private boolean checkParam(String str){...}

53  日志打印输出的 POJO 类必须重写 toString 方法,否则只输出此对象的 hashCode 值(地址值),没啥参考意义。

54  大量地输出无效日志,不利于系统性能提升,也不利于快速定位错误点。纪录日志时请

思考:这些日志真的有人看吗?看到这条日志你能做什么?能不能给问题排查带来好处?

55  中括号是数组类型的一部分,数组定义如下:String[] args;

反例:请勿使用 String args[]的方式来定义

56  抽象类命名使用 Abstract 或 Base 开头;异常类命名使用 Exception 结尾;测试类命

名以它要测试的类的名称开始,以 Test 结尾。

你可能感兴趣的:(JAVA开发规范)