使用阿里巴巴开发规范扫描我的博客发现的问题总结

一、 在if/else/for/while/do语句中必须使用大括号,即使只有一行代码,避免使用下面的形式(发现1处):

1
if (condition) statements;

二应该写成下面这样的形式:

1
2
3
if (flag) {
System.out.println("hello world");
}

二、 所有的覆写方法,必须加@Override注解。 反例:getObject()与get0bject()的问题。一个是字母的O,一个是数字的0,加@Override可以准确判断是否覆盖成功。另外,如果在抽象类中对方法签名进行修改,其实现类会马上编译报错(发现25处)。

三、 Object的equals方法容易抛空指针异常,应使用常量或确定有值的对象来调用equals(发现62处)。

1
2
3
4
5
6
public void f(String str){
String inner = "hi";
if (inner.equals(str)) {
System.out.println("hello world");
}
}

四、 SimpleDateFormat 是线程不安全的类,一般不要定义为static变量,如果定义为static,必须加锁,或者使用DateUtils工具类(发现62处)。

说明:如果是JDK8的应用,可以使用instant代替Date,LocalDateTime代替Calendar,DateTimeFormatter代替SimpleDateFormat,官方给出的解释:simple beautiful strong immutable thread-safe。

Positive example 1:

1
2
3
4
5
6
7
8
9
private static final String FORMAT = "yyyy-MM-dd HH:mm:ss";
public String getFormat(Date date){
SimpleDateFormat dateFormat = new SimpleDateFormat(FORMAT);
return sdf.format(date);
}
```


Positive example 2:

private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);
public void getFormat(){
synchronized (sdf){
sdf.format(new Date());
….;
}

1
2
3
4
        


Positive example 3:

private static final ThreadLocal DATE_FORMATTER = new ThreadLocal() {
@Override
protected DateFormat initialValue() {
return new SimpleDateFormat(“yyyy-MM-dd”);
}
};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

> 我玩意说是这么说,但是经过我的实验,发现SimpleDateFormat的parse确实需要加锁,但是format方法不需要。

五、 不能使用过时的类或方法。 说明:java.net.URLDecoder 中的方法decode(String encodeStr) 这个方法已经过时,应该使用双参数decode(String source, String encode)(发现1处)。

接口提供方既然明确是过时接口,那么有义务同时提供新的接口;作为调用方来说,有义务去考证过时方法的新实现是什么。

六、常量命名应该全部大写,单词间用下划线隔开,力求语义表达完整清楚,不要嫌名字长(发现6处)

```
public class ConstantNameDemo {

/**
* max stock count
*/
public static final Long MAX_STOCK_COUNT = 50000L;
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public enum TestEnum {
/**
* agree
*/
agree("agree"),
/**
* reject
*/
reject("reject");

private String action;

TestEnum(String action) {
this.action = action;
}

public String getAction() {
return action;
}
}

八、 方法名、参数名、成员变量、局部变量都统一使用lowerCamelCase,必须遵从驼峰形式(发现4处)

九、线程资源必须通过线程池提供,不允许在应用中自行显式创建线程。 说明:使用线程池的好处是减少在创建和销毁线程上所花的时间以及系统资源的开销,解决资源不足的问题。如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或者“过度切换”的问题(发现8处)。

1
2
3
4
5
6
7
8
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
.setNameFormat("demo-pool-%d").build();
ExecutorService singleThreadPool = new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());

singleThreadPool.execute(()-> System.out.println(Thread.currentThread().getName()));
singleThreadPool.shutdown();

十、 不允许任何魔法值(即未经定义的常量)直接出现在代码中(发现212处)。

Negative example:

1
2
3
4
5
6
7
//Magic values, except for predefined, are forbidden in coding.
if (key.equals("Id#taobao_1")) {
//...
}
```

Positive example:

String KEY_PRE = “Id#taobao_1”;
if (KEY_PRE.equals(key)) {
//…
}

1
2
3


十一、中括号是数组类型的一部分,数组定义如下(发现19处):

String[] args;

String[] a = new String[3];

1
2
3
4

十二、及时清理不再使用的代码段或配置信息。 说明:对于垃圾代码或过时配置,坚决清理干净,避免程序过度臃肿,代码冗余(发现2处)。

Positive example: For codes which are temporarily removed and likely to be reused, use /// to add a reasonable note.

public static void hello() {
/// Business is stopped temporarily by the owner.
// Business business = new Business();
// business.active();
System.out.println(“it’s finished”);
}

1
2

十三、所有的抽象方法(包括接口中的方法)必须要用javadoc注释、除了返回值、参数、异常说明外,还必须指出该方法做什么事情,实现什么功能。 说明:如有实现和调用注意事项,请一并说明(发现2处)。

/**

  • fetch data by rule id
  • @param ruleId rule id
  • @param page page number
  • @param jsonContext json format context
  • @return Result
    */
    Result fetchDataByRuleId(Long ruleId, Integer page, String jsonContext);
    1
    2

    十四、所有的类都必须添加创建者信息。 说明:在设置模板时,注意IDEA的@author为${USER},而eclipse的@author为${user},大小写有区别,而日期的设置统一为yyyy/MM/dd的格式(发现45处)。

/**

  • Demo class
  • @author keriezhang
  • @date 2016/10/31
    */
    public class CodeNoteDemo {
    }
    1
    2
    3
    4

    十五、集合初始化时,指定集合初始值大小。 说明:HashMap使用如下构造方法进行初始化,如果暂时无法确定集合大小,那么指定默认值(16)即可(发现6处)。

    Negative example:

Map<String, String> map = new HashMap<String, String>();

1
2
        
Positive example:

Map<String, String> map = new HashMap<String, String>(16);

1
2
3
4
5
6

十六、类名使用UpperCamelCase风格,必须遵从驼峰形式,但以下情形例外:(领域模型的相关命名)DO / BO / DTO / VO / DAO(发现1处)

十七、除常用方法(如getXxx/isXxx)等外,不要在条件判断中执行复杂的语句,将复杂逻辑判断的结果赋值给一个有意义的布尔变量,以提高可读性。 说明:很多if语句内的逻辑相当复杂,阅读者需要分析条件表达式的最终结果,才能明确什么样的条件执行什么样的语句,那么,如果阅读者分析逻辑表达式错误呢?

Negative example:

if ((file.open(fileName, “w”) != null) && (…) || (…)) {
// …
}

1
2
            
Positive example:

boolean existed = (file.open(fileName, “w”) != null) && (…) || (…);
if (existed) {
//…
}

1
2

十八、类、类属性、类方法的注释必须使用javadoc规范,使用/**内容*/格式,不得使用//xxx方式和/*xxx*/方式。 说明:在IDE编辑窗口中,javadoc方式会提示相关注释,生成javadoc可以正确输出相应注释;在IDE中,工程调用方法时,不进入方法即可悬浮提示方法、参数、返回值的意义,提高阅读效率(发现2处)。

/**

  • XXX class function description.
    /
    public class XxClass implements Serializable {
    private static final long serialVersionUID = 113323427779853001L;
    /**

    • id
      */
      private Long id;
      /**
    • title
      */
      private String title;

      /**

    • find by id
    • @param ruleId rule id
    • @param page start from 1
    • @return Result
      */
      public Result funcA(Long ruleId, Integer page) {
      return null;
      }
      }
      1
      2
              			
      十九、方法内部单行注释,在被注释语句上方另起一行,使用//注释。方法内部多行注释使用/* */注释。注意与代码对齐(发现12处)。

public void method() {
// Put single line comment above code. (Note: align ‘//‘ comment with code)
int a = 3;

/**
* Some description about follow code. (Note: align '/**' comment with code)
*/
int b = 4;

}
`