《阿里巴巴Java規(guī)約插件》使用總結(jié)

前言

小編用自己的項(xiàng)目做白老鼠,試試這個(gè)阿里巴巴榮譽(yù)出品的《Java規(guī)約插件》


結(jié)果居然有4800+條問題?。『喼眹樀眯【帒岩扇松心居校??(默哀0.01秒)小編依舊懷著認(rèn)真的科學(xué)精神進(jìn)入試驗(yàn)田(快開車,別廢話?。H缦肓私馊绾伟惭b插件和插件的使用技巧請猛戳:http://www.itdecent.cn/p/834899aa90b4

入題

掃描出三個(gè)分類結(jié)果(類jira的bug優(yōu)先級分為:blocker,critical,major,minor,trivial)

  • Blocker 有妨礙的
  • Critical 緊要的
  • Major 嚴(yán)重的

具體的語法問題,值得學(xué)習(xí)下:

Blocker 有妨礙的
  • 在if/else/for/while/do語句中必須使用大括號,即使只有一行代碼,避免使用下面的形式:if (condition) statements;

  • 在使用正則表達(dá)式時(shí),利用好其預(yù)編譯功能,可以有效加快正則匹配速度。
    說明:不要在方法體內(nèi)定義:Pattern pattern = Pattern.compile(規(guī)則);
    public class XxxClass {
    // Use precompile
    private static Pattern NUMBER_PATTERN = Pattern.compile("[0-9]+");
    public Pattern getNumberPattern() {
    // Avoid use Pattern.compile in method body.
    Pattern localPattern = Pattern.compile("[0-9]+");
    return localPattern;
    }
    }

  • 多線程并行處理定時(shí)任務(wù)時(shí),Timer運(yùn)行多個(gè)TimeTask時(shí),只要其中之一沒有捕獲拋出的異常,其它任務(wù)便會(huì)自動(dòng)終止運(yùn)行,使用ScheduledExecutorService則沒有這個(gè)問題。 //org.apache.commons.lang3.concurrent.BasicThreadFactory
    ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1,
    new BasicThreadFactory.Builder().namingPattern("example-schedule-pool-%d").daemon(true).build());
    executorService.scheduleAtFixedRate(new Runnable() {
    @Override
    public void run() {
    //do something
    }
    },initialDelay,period, TimeUnit.HOURS);

  • 所有的覆寫方法,必須加@Override注解。 反例:getObject()與get0bject()的問題。一個(gè)是字母的O,一個(gè)是數(shù)字的0,加@Override可以準(zhǔn)確判斷是否覆蓋成功。另外,如果在抽象類中對方法簽名進(jìn)行修改,其實(shí)現(xiàn)類會(huì)馬上編譯報(bào)錯(cuò)。

  • 線程池不允許使用Executors去創(chuàng)建,而是通過ThreadPoolExecutor的方式,這樣的處理方式讓寫的同學(xué)更加明確線程池的運(yùn)行規(guī)則,規(guī)避資源耗盡的風(fēng)險(xiǎn)。 說明:Executors各個(gè)方法的弊端:
    1)newFixedThreadPool和newSingleThreadExecutor:
    ??主要問題是堆積的請求處理隊(duì)列可能會(huì)耗費(fèi)非常大的內(nèi)存,甚至OOM。
    2)newCachedThreadPool和newScheduledThreadPool:
    ??主要問題是線程數(shù)最大數(shù)是Integer.MAX_VALUE,可能會(huì)創(chuàng)建數(shù)量非常多的線程,甚至OOM。

Positive example 1:
//org.apache.commons.lang3.concurrent.BasicThreadFactory
ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1,
new BasicThreadFactory.Builder().namingPattern("example-schedule-pool-%d").daemon(true).build());

Positive example 2:
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
.setNameFormat("demo-pool-%d").build();

//Common Thread Pool
ExecutorService pool = new ThreadPoolExecutor(5, 200,
     0L, TimeUnit.MILLISECONDS,
     new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());

pool.execute(()-> System.out.println(Thread.currentThread().getName()));
pool.shutdown();//gracefully shutdown

Positive example 3:
<bean id="userThreadPool"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="10" />
<property name="maxPoolSize" value="100" />
<property name="queueCapacity" value="2000" />

<property name="threadFactory" value= threadFactory />
    <property name="rejectedExecutionHandler">
        <ref local="rejectedExecutionHandler" />
    </property>
</bean>
//in code
userThreadPool.execute(thread);
  • 避免通過一個(gè)類的對象引用訪問此類的靜態(tài)變量或靜態(tài)方法,無謂增加編譯器解析成本,直接用類名來訪問即可。

  • Critical 緊要的

Object的equals方法容易拋空指針異常,應(yīng)使用常量或確定有值的對象來調(diào)用equals。

public void f(String str){
    String inner = "hi";
    if(inner.equals(str)){
        System.out.println("hello world");
    }
}
  • SimpleDateFormat 是線程不安全的類,一般不要定義為static變量,如果定義為static,必須加鎖,或者使用DateUtils工具類。 說明:如果是JDK8的應(yīng)用,可以使用instant代替Date,LocalDateTime代替Calendar,DateTimeFormatter代替SimpleDateFormat,官方給出的解釋:simple beautiful strong immutable thread-safe。

Positive example 1:
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());
….;
}

Positive example 3:
private static final ThreadLocal<DateFormat> DATE_FORMATTER = new ThreadLocal<DateFormat>() {
@Override
protected DateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd");
}
};

  • 不能使用過時(shí)的類或方法。 說明:java.net.URLDecoder 中的方法decode(String encodeStr) 這個(gè)方法已經(jīng)過時(shí),應(yīng)該使用雙參數(shù)decode(String source, String encode)。接口提供方既然明確是過時(shí)接口,那么有義務(wù)同時(shí)提供新的接口;作為調(diào)用方來說,有義務(wù)去考證過時(shí)方法的新實(shí)現(xiàn)是什么。

  • 在一個(gè)switch塊內(nèi),每個(gè)case要么通過break/return等來終止,要么注釋說明程序?qū)⒗^續(xù)執(zhí)行到哪一個(gè)case為止;在一個(gè)switch塊內(nèi),都必須包含一個(gè)default語句并且放在最后,即使它什么代碼也沒有。

    switch( x ){
    case 1 :
    break ;
    case 2 :
    break ;
    default :
    }

  • 常量命名應(yīng)該全部大寫,單詞間用下劃線隔開,力求語義表達(dá)完整清楚,不要嫌名字長

    public class ConstantNameDemo {

    /**

    • max stock count
      */
      public static final Long MAX_STOCK_COUNT = 50000L;
  • 所有的枚舉類型字段必須要有注釋,說明每個(gè)數(shù)據(jù)項(xiàng)的用途。
    public enum TestEnum {
    /**
    * agree
    /
    agree("agree"),
    /
    *
    * reject
    */
    reject("reject");

      private String action;
    
      TestEnum(String action) {
          this.action = action;
      }
    
      public String getAction() {
          return action;
      }
    

    }

  • 所有編程相關(guān)的命名均不能以下劃線或美元符號開始

  • 抽象類命名使用Abstract或Base開頭

    abstract class BaseControllerDemo{
    }

    abstract class AbstractActionDemo{
    }

  • 方法名、參數(shù)名、成員變量、局部變量都統(tǒng)一使用lowerCamelCase,必須遵從駝峰形式

  • Major 嚴(yán)重的
  • 不允許任何魔法值(即未經(jīng)定義的常量)直接出現(xiàn)在代碼中。
    Negative example:
    //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.equals(KEY_PRE)){
    //...
    }

  • 中括號是數(shù)組類型的一部分,數(shù)組定義如下:String[] args

    String[] a = new String[3];

  • 及時(shí)清理不再使用的代碼段或配置信息。 說明:對于垃圾代碼或過時(shí)配置,堅(jiān)決清理干凈,避免程序過度臃腫,代碼冗余。
    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");
    }

  • 循環(huán)體內(nèi),字符串的聯(lián)接方式,使用StringBuilder的append方法進(jìn)行擴(kuò)展。 說明:反編譯出的字節(jié)碼文件顯示每次循環(huán)都會(huì)new出一個(gè)StringBuilder對象,然后進(jìn)行append操作,最后通過toString方法返回String對象,造成內(nèi)存資源浪費(fèi)。
    反例:
    String result;
    for (String string : tagNameList) {
    result = result + string;
    }
    正例:
    StringBuilder stringBuilder = new StringBuilder();
    for (String string : tagNameList) {
    stringBuilder.append(string);
    }
    String result = stringBuilder.toString();

  • 所有的抽象方法(包括接口中的方法)必須要用javadoc注釋、除了返回值、參數(shù)、異常說明外,還必須指出該方法做什么事情,實(shí)現(xiàn)什么功能。 說明:如有實(shí)現(xiàn)和調(diào)用注意事項(xiàng),請一并說明。
    /**

    • fetch data by rule id
    • @param ruleId rule id
    • @param page page number
    • @param jsonContext json format context
    • @return Result<XxxxDO>
      */
      Result<XxxxDO> fetchDataByRuleId(Long ruleId, Integer page, String jsonContext);
  • 所有的類都必須添加創(chuàng)建者信息。 說明:在設(shè)置模板時(shí),注意IDEA的@author為${USER},而eclipse的@author為${user},大小寫有區(qū)別,而日期的設(shè)置統(tǒng)一為yyyy/MM/dd的格式。
    /**

    • Demo class
    • @author keriezhang
    • @date 2016/10/31
      */
      public class CodeNoteDemo {
      }
  • 方法內(nèi)部單行注釋,在被注釋語句上方另起一行,使用//注釋。方法內(nèi)部多行注釋使用/* */注釋。注意與代碼對齊。
    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;
    

    }

  • 類、類屬性、類方法的注釋必須使用javadoc規(guī)范,使用/內(nèi)容/格式,不得使用//xxx方式和/xxx/方式。 說明:在IDE編輯窗口中,javadoc方式會(huì)提示相關(guān)注釋,生成javadoc可以正確輸出相應(yīng)注釋;在IDE中,工程調(diào)用方法時(shí),不進(jìn)入方法即可懸浮提示方法、參數(shù)、返回值的意義,提高閱讀效率。
    /
    *

    • 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<Xxxx>
       */
      public Result<Xxxx> funcA(Long ruleId, Integer page) {
          return null;
      }
    

    }

  • 類名使用UpperCamelCase風(fēng)格,必須遵從駝峰形式,但以下情形例外:(領(lǐng)域模型的相關(guān)命名)DO / BO / DTO / VO / DAO

  • 除常用方法(如getXxx/isXxx)等外,不要在條件判斷中執(zhí)行復(fù)雜的語句,將復(fù)雜邏輯判斷的結(jié)果賦值給一個(gè)有意義的布爾變量,以提高可讀性。 說明:很多if語句內(nèi)的邏輯相當(dāng)復(fù)雜,閱讀者需要分析條件表達(dá)式的最終結(jié)果,才能明確什么樣的條件執(zhí)行什么樣的語句,那么,如果閱讀者分析邏輯表達(dá)式錯(cuò)誤呢?

Negative example:
if ((file.open(fileName, "w") != null) && (...) || (...)) {
...
}

Positive example:
boolean existed = (file.open(fileName, "w") != null) && (...) || (...);
if (existed) {
...
}

  • 集合初始化時(shí),指定集合初始值大小。 說明:HashMap使用如下構(gòu)造方法進(jìn)行初始化,如果暫時(shí)無法確定集合大小,那么指定默認(rèn)值(16)即可。

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

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

小結(jié)

總的來說,阿里巴巴Java規(guī)約插件還是對項(xiàng)目很有幫助的,大家用起來吧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容