阿里Java開發規約(1)


本文是對阿里插件中規約的詳細解釋一,關於插件使用,請參考這里

 

1. ArrayList的subList結果不可強轉成ArrayList,否則會拋出ClassCastException異常。 說明:禁止強轉,如果需要用到集合特性方法,請新建一個集合,然后置入sublist,new 集合(sublist結果)。

Negative example:
   List<String> list = new ArrayList<String>(); list.add("22"); //warn List<String> test = (ArrayList<String>) list.subList(0, 1); Positive example: List<String> list2 = new ArrayList<String>(list.subList(0, 1));

 

2. iBATIS自帶的queryForList(String statementName,int start,int size)不推薦使用 

3. long或者Long初始賦值時,必須使用大寫的L,不能是小寫的l,小寫容易跟數字1混淆,造成誤解。 (注:規約)

Negative example: 
//It is hard to tell whether it is number 11 or Long 1.
Long warn = 1l; Positive example: Long notwarn = 1L; 

 

4. Map/Set的key為自定義對象時,必須重寫hashCode和equals。 

注:兩個相同的對象,要求hashcode必須相同,但反之無此要求。因為用hashcode的本意在於提高效率,
所以有時在比較對象時(比如map的contain等),會先比較hashcode,如果hashcode不等,就直接返回結果
關於hashCode和equals的處理,遵循如下規則:  
1) 只要重寫equals,就必須重寫hashCode。  
2) 因為Set存儲的是不重復的對象,依據hashCode和equals進行判斷,所以Set存儲的對象必須重寫這兩個方法。  
3) 如果自定義對象作為Map的鍵,那么必須重寫hashCode和equals。

 

5. Object的equals方法容易拋空指針異常,應使用常量或確定有值的對象來調用equals。 

6. POJO類中的任何布爾類型的變量,都不要加is,否則部分框架解析會引起序列化錯誤

public class DemoDO{
        Boolean success;
        Boolean delete;
}     

 

7. POJO類必須寫toString方法。(約定)

使用工具類source> generate toString時,如果繼承了另一個POJO類,注意在前面加一下super.toString。 說明:在方法執行拋出異常時,可以直接調用POJO的toString()方法打印其屬性值,便於排查問題。

public class ToStringDemo extends Super{ private String secondName; @Override public String toString() { return super.toString() + "ToStringDemo{" + "secondName='" + secondName + '\'' + '}'; } } class Super { private String firstName; @Override public String toString() { return "Super{" + "firstName=" + firstName + '\'' + '}'; } }

 

8. SimpleDateFormat 是線程不安全的類,一般不要定義為static變量,如果定義為static,必須加鎖,或者使用DateUtils工具類。 

說明:如果是JDK8的應用,可以使用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"); } };

 

9. 不允許任何魔法值(即未經定義的常量)直接出現在代碼中

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)){ //...  }

 

10. 不能使用過時的類或方法。 

說明:java.net.URLDecoder 中的方法decode(String encodeStr) 這個方法已經過時,應該使用雙參數decode(String source, String encode)。
接口提供方既然明確是過時接口,那么有義務同時提供新的接口;作為調用方來說,有義務去考證過時方法的新實現是什么。

 

11. 不能在finally塊中使用return,finally塊中的return返回后方法結束執行,不會再執行try塊中的return語句。

     注:這里阿里沒有解釋清楚,其實指的是如果try中語句出現異常,因為finally的return語句,會造成異常丟失的情況

Negative example:
    public static Long readFileLength(String fileName) { try { File file = new File(fileName); RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r"); return randomAccessFile.length(); } catch (Exception e) { logger.error(e.getMessage(), e); } finally { countDownLatch.countDown(); return 0L; } }

 

12. 不要在foreach循環里進行元素的remove/add操作,remove元素請使用Iterator方式。

     注:會造成異常

 Negative example:   
   List<String> originList = new ArrayList<String>(); originList.add("22"); for (String item : originList) { //warn list.add("bb"); } 

 

13. 中括號是數組類型的一部分,數組定義如下:String[] args  (注:約定)

14. 事務場景中,拋出異常被catch后,如果需要回滾,一定要手動回滾事務。

     注:spring中@Transactional默認當拋出RuntimeException時會自動回滾

Positive example 1:
    /**
     * @author caikang
     * @date 2017/04/07
     */ @Service @Transactional(rollbackFor = Exception.class) public class UserServiceImpl implements UserService { @Override public void save(User user) { //some code //db operation  } } Positive example 2: /** * @author caikang * @date 2017/04/07 */ @Service public class UserServiceImpl implements UserService { @Override @Transactional(rollbackFor = Exception.class) public void save(User user) { //some code //db operation  } } Positive example 3: /** * @author caikang * @date 2017/04/07 */ @Service public class UserServiceImpl implements UserService { @Autowired private DataSourceTransactionManager transactionManager; @Override @Transactional public void save(User user) { DefaultTransactionDefinition def = new DefaultTransactionDefinition(); // explicitly setting the transaction name is something that can only be done programmatically def.setName("SomeTxName"); def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); TransactionStatus status = transactionManager.getTransaction(def); try { // execute your business logic here //db operation } catch (Exception ex) { transactionManager.rollback(status); throw ex; } } }

 

15. 使用CountDownLatch進行異步轉同步操作,每個線程退出前必須調用countDown方法,線程執行代碼注意catch異常,確保countDown方法可以執行,避免主線程無法執行至await方法,直到超時才返回結果。 說明:注意,子線程拋出異常堆棧,不能在主線程try-catch到。

   注:關於CountDownLatch,用於需子線程結束主線程才能繼續的場景,可以參考這里

    /**
     * @author caikang
     * @date 2017/04/07
     */
    public class CountDownExample {
        public void operate(CountDownLatch countDownLatch){ try{ System.out.println("business logic"); }catch (RuntimeException e){ // do something }finally { countDownLatch.countDown(); } } }

 

 16. 使用工具類Arrays.asList()把數組轉換成集合時,不能使用其修改集合相關的方法,它的add/remove/clear方法會拋出UnsupportedOperationException異常。

       注:看Arrays.asList源碼可以知道這個方法生成的是Arrays里面的一個size固定的內部類ArrayList,而不是常用的ArrayList,雖然它也實現List接口

Positive example:
   List<String> t   = Arrays.asList("a","b","c"); 
   //warn
   t.add("22");
   //warn
   t.remove("22");
   //warn
   t.clear();

 

17. 使用集合轉數組的方法,必須使用集合的toArray(T[] array),傳入的是類型完全一樣的數組,大小就是list.size()

Negative example:  
   Integer[] a = (Integer [])c.toArray();
        
        
Positive example: 
   Integer[] b = (Integer [])c.toArray(new Integer[c.size()]); 

 

18. 關於基本數據類型與包裝數據類型的使用標准如下:

 1) 所有的POJO類屬性必須使用包裝數據類型。
 2) RPC方法的返回值和參數必須使用包裝數據類型。
 3) 所有的局部變量推薦使用基本數據類型。 說明:POJO類屬性沒有初值是提醒使用者在需要使用時,必須自己顯式地進行賦值,任何NPE問題,或者入庫檢查,都由使用者來保證。

注:NPE:NullPointerException,這樣寫是為了統一,用戶顯式賦值,要比有默認值為前提不容易出錯

    public class DemoDO {
        String str;
        Integer a;
    }

 

19. 創建線程或線程池時請指定有意義的線程名稱,方便出錯時回溯。創建線程池的時候請使用帶ThreadFactory的構造函數,並且提供自定義ThreadFactory實現或者使用第三方實現。

    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();
    
        
            
    public class TimerTaskThread extends Thread {
        public TimerTaskThread(){
        super.setName("TimerTaskThread"); …
    }

 

20.  包名統一使用小寫,點分隔符之間有且僅有一個自然語義的英語單詞。包名統一使用單數形式,但是類名如果有復數含義,類名可以使用復數形式

com.alibaba.mpp.util / com.taobao.tddl.domain.dto

 








 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM