2019獨角獸企業重金招聘Python工程師標準>>>
一、編程規約:
(一)命名風格
1. 【強制】 代碼中的命名均不能以下劃線或美元符號開始,也不能以下劃線或美元符號結束。
反例: _name / __name / $Object / name_ / name$ / Object$
2.【強制】類名使用 UpperCamelCase 風格,必須遵從駝峰形式,但以下情形例外: DO / BO / DTO / VO / AO
正例: MarcoPolo / UserDO / XmlService / TcpUdpDeal / TaPromotion
3.【強制】 POJO 類中布爾類型的變量,都不要加 is,否則部分框架解析會引起序列化錯誤。
反例: 定義為基本數據類型 Boolean isDeleted; 的屬性,它的方法也是 isDeleted(), RPC框架在反向解析的時候, “以為”對應的屬性名稱是 deleted,導致屬性獲取不到,進而拋出異常。
4.【強制】包名統一使用小寫,點分隔符之間有且僅有一個自然語義的英語單詞。包名統一使用單數形式,但是類名如果有復數含義,類名可以使用復數形式。
正例: 應用工具類包名為 com.alibaba.open.util、類名為 MessageUtils( 此規則參考spring 的框架結構)
5. 【參考】各層命名規約:
Service/DAO 層方法命名規約
- ?獲取單個對象的方法用 get 做前綴。
- ?獲取多個對象的方法用 list 做前綴。
- ?獲取統計值的方法用 count 做前綴。
- ?插入的方法用 save/insert 做前綴。
- ?刪除的方法用 remove/delete 做前綴。
- ?修改的方法用 update 做前綴。
領域模型命名規約
- ?數據對象: xxxDO, xxx 即為數據表名。
- ?數據傳輸對象: xxxDTO, xxx 為業務領域相關的名稱。
- ?展示對象: xxxVO, xxx 一般為網頁名稱。
- ?POJO 是 DO/DTO/BO/VO 的統稱,禁止命名成 xxxPOJO。
(二)常量定義
1.【推薦】不要使用一個常量類維護所有常量, 按常量功能進行歸類,分開維護。
正例: 緩存相關常量放在類 CacheConsts 下; 系統配置相關常量放在類 ConfigConsts 下。
2.【推薦】常量的復用層次有五層:跨應用共享常量、應用內共享常量、子工程內共享常量、包內共享常量、類內共享常量。
1) 跨應用共享常量:放置在二方庫中,通常是 client.jar 中的 constant 目錄下。
2) 應用內共享常量:放置在一方庫中, 通常是 modules 中的 constant 目錄下。
反例: 易懂變量也要統一定義成應用內共享常量,兩位攻城師在兩個類中分別定義了表示“是”的變量:
類 A 中: public static final String YES = "yes";
類 B 中: public static final String YES = "y";
A.YES.equals(B.YES),預期是 true,但實際返回為 false,導致線上問題。
3) 子工程內部共享常量:即在當前子工程的 constant 目錄下。
4) 包內共享常量:即在當前包下單獨的 constant 目錄下。
5) 類內共享常量:直接在類內部 private static final 定義。
3.【推薦】如果變量值僅在一個范圍內變化,且帶有名稱之外的延伸屬性, 定義為枚舉類。下面正例中的數字就是延伸信息,表示星期幾。
正例: public Enum { MONDAY(1), TUESDAY(2), WEDNESDAY(3), THURSDAY(4), FRIDAY(5), SATURDAY(6),SUNDAY(7);}
?
(三)代碼格式
1.【強制】 左小括號和字符之間不出現空格; 同樣,右小括號和字符之間也不出現空格。詳見第 5 條下方正例提示
反例: if (空格 a == b 空格)
2.【強制】 if/for/while/switch/do 等保留字與括號之間都必須加空格。
3.【強制】 采用 4 個空格縮進,禁止使用 tab 字符。
4.【強制】 注釋的雙斜線與注釋內容之間有且僅有一個空格。
5.【強制】方法參數在定義和傳入時,多個參數逗號后邊必須加空格。
6.【強制】 IDE 的 text file encoding 設置為 UTF-8; IDE 中文件的換行符使用 Unix 格式,不要使用 Windows 格式。
7. 【推薦】方法體內的執行語句組、變量的定義語句組、不同的業務邏輯之間或者不同的語義之間插入一個空行。相同業務邏輯和語義之間不需要插入空行。
說明: 沒有必要插入多個空行進行隔開。
(四)OOP 規約
1. 【強制】避免通過一個類的對象引用訪問此類的靜態變量或靜態方法,無謂增加編譯器解析成本,直接用類名來訪問即可。
2. 【強制】所有的覆寫方法,必須加@Override 注解。
說明: 加@Override可以準確判斷是否覆蓋成功。另外,如果在抽象類中對方法簽名進行修改,其實現類會馬上編譯報錯。
3.【強制】相同參數類型,相同業務含義,才可以使用 Java 的可變參數,避免使用 Object。
說明: 可變參數必須放置在參數列表的最后。 ( 提倡同學們盡量不用可變參數編程)
正例: public User getUsers(String type, Integer... ids) {...}
4. 【強制】外部正在調用或者二方庫依賴的接口,不允許修改方法簽名,避免對接口調用方產生
影響。接口過時必須加@Deprecated 注解,并清晰地說明采用的新接口或者新服務是什么。
5. 【強制】不能使用過時的類或方法。
6.【強制】 Object 的 equals 方法容易拋空指針異常,應使用常量或確定有值的對象來調用equals。
正例: "test".equals(object);
說明: 推薦使用 java.util.Objects#equals( JDK7 引入的工具類)
7.【強制】所有的相同類型的包裝類對象之間值的比較,全部使用 equals 方法比較。
說明: 對于 Integer var = ? 在-128 至 127 范圍內的賦值, Integer 對象是在IntegerCache.cache 產生,會復用已有對象,這個區間內的 Integer 值可以直接使用==進行判斷,但是這個區間之外的所有數據,都會在堆上產生,并不會復用已有對象,這是一個大坑,推薦使用 equals 方法進行判斷
8. 關于基本數據類型與包裝數據類型的使用標準如下:
- 【強制】 所有的 POJO 類屬性必須使用包裝數據類型。
- 【強制】 RPC 方法的返回值和參數必須使用包裝數據類型。
- 【 推薦】 所有的局部變量使用基本數據類型。
說明: POJO 類屬性沒有初值是提醒使用者在需要使用時,必須自己顯式地進行賦值,任何NPE 問題,或者入庫檢查,都由使用者來保證。
正例: 數據庫的查詢結果可能是 null,因為自動拆箱,用基本數據類型接收有 NPE 風險。
9.【強制】定義 DO/DTO/VO 等 POJO 類時,不要設定任何屬性默認值。
10.【強制】序列化類新增屬性時,請不要修改 serialVersionUID 字段,避免反序列失敗; 如果完全不兼容升級,避免反序列化混亂,那么請修改 serialVersionUID 值。
說明: 注意 serialVersionUID 不一致會拋出序列化運行時異常。
11.?【強制】構造方法里面禁止加入任何業務邏輯,如果有初始化邏輯,請放在 init 方法中。
12.【推薦】 類內方法定義順序依次是:公有方法或保護方法 > 私有方法 > getter/setter方法。
13.【推薦】循環體內,字符串的連接方式,使用 StringBuilder 的 append 方法進行擴展。
說明: 反編譯出的字節碼文件顯示每次循環都會 new 出一個 StringBuilder 對象,然后進行append 操作,最后通過 toString 方法返回 String 對象,造成內存資源浪費。
反例:
String str = "start";
for (int i = 0; i < 100; i++) {
str = str + "hello";
}
(五)集合處理
1. 【強制】 關于 hashCode 和 equals 的處理,遵循如下規則:
- 只要重寫 equals,就必須重寫 hashCode。
- 因為 Set 存儲的是不重復的對象,依據 hashCode 和 equals 進行判斷,所以 Set 存儲的對象必須重寫這兩個方法。
- 如果自定義對象做為 Map 的鍵,那么必須重寫 hashCode 和 equals。
說明: String 重寫了 hashCode 和 equals 方法,所以我們可以非常愉快地使用 String 對象作為 key 來使用
2.【強制】 ArrayList的subList結果不可強轉成ArrayList,否則會拋出 ClassCastException異常, 即 java.util.RandomAccessSubList cannot be cast to java.util.ArrayList.
說明: subList 返回的是 ArrayList 的內部類 SubList,并不是 ArrayList ,而是ArrayList 的一個視圖,對于 SubList 子列表的所有操作最終會反映到原列表上。
3.【強制】在 subList 場景中, 高度注意對原集合元素個數的修改,會導致子列表的遍歷、增加、
刪除均會產生 ConcurrentModificationException 異常。
4.【強制】使用集合轉數組的方法,必須使用集合的 toArray(T[] array),傳入的是類型完全一樣的數組,大小就是 list.size()。
說明: 使用 toArray 帶參方法,入參分配的數組空間不夠大時, toArray 方法內部將重新分配內存空間,并返回新數組地址; 如果數組元素大于實際所需,下標為[ list.size() ]的數組元素將被置為 null,其它數組元素保持原值,因此最好將方法入參數組大小定義與集合元素個數一致。
正例:
List<String> list = new ArrayList<String>(2);
list.add("abc");
list.add("def");
String[] array = new String[list.size()];
array = list.toArray(array);
for (int i = 0 ; i < array.length ; i++ ){System.out.println("===="+array[i]);
}
反例: 直接使用 toArray 無參方法存在問題,此方法返回值只能是 Object[]類,若強轉其它類型數組將出現 ClassCastException 錯誤。
5.【強制】使用工具類 Arrays.asList()把數組轉換成集合時,不能使用其修改集合相關的方法,它的 add/remove/clear 方法會拋出 UnsupportedOperationException 異常。
說明: asList 的返回對象是一個 Arrays 內部類,并沒有實現集合的修改方法。Arrays.asList體現的是適配器模式,只是轉換接口,后臺的數據仍是數組。
String[] str = new String[] { "you", "wu" };
List list = Arrays.asList(str);
第一種情況: list.add("yangguanbao"); 運行時異常。
第二種情況: str[0] = "gujin"; 那么 list.get(0)也會隨之修改。
6.【強制】泛型通配符<? extends T>來接收返回的數據,此寫法的泛型集合不能使用 add 方法, 而<? super T>不能使用 get 方法,做為接口調用賦值時易出錯。
說明: 擴展說一下 PECS(Producer Extends Consumer Super)原則: 第一、 頻繁往外讀取內容的,適合用<? extends T>。 第二、 經常往里插入的,適合用<? super T>。
7. 【強制】不要在 foreach 循環里進行元素的 remove/add 操作。 remove 元素請使用 Iterator方式,如果并發操作,需要對 Iterator 對象加鎖
正例:
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {String item = iterator.next();if (刪除元素的條件) {iterator.remove();}
}
反例:
List<String> list = new ArrayList<String>();
list.add("1");
list.add("2");
for (String item : list) {if ("1".equals(item)) {list.remove(item);}
}
8. 【強制】 在 JDK7 版本及以上, Comparator 要滿足如下三個條件,不然 Arrays.sort,
Collections.sort 會報 IllegalArgumentException 異常。
說明: 三個條件如下
1) x, y 的比較結果和 y, x 的比較結果相反。
2) x>y, y>z, 則 x>z。
3) x=y, 則 x, z 比較結果和 y, z 比較結果相同。
9. 【推薦】集合初始化時, 指定集合初始值大小。
說明: HashMap 使用 HashMap(int initialCapacity) 初始化,
說明: HashMap 使用 HashMap(int initialCapacity) 初始化,
正例:initialCapacity = (需要存儲的元素個數 / 負載因子) + 1。注意負載因子 ( 即 loaderfactor) 默認為 0.75, 如果暫時無法確定初始值大小,請設置為 16(即默認值) 。
反例: HashMap 需要放置 1024 個元素, 由于沒有設置容量初始大小,隨著元素不斷增加,容量 7 次被迫擴大, resize 需要重建 hash 表,嚴重影響性能。
10. 【推薦】使用 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 值組合集合。
11. 【推薦】高度注意 Map 類集合 K/V 能不能存儲 null 值的情況,如下表格:
集合類? ? ? ? ?Key? ? ? ? ? ? ? ?Value? ? ? ? ? ? ?Super? ? ? ? ?說明
Hashtable 不允許為 null 不允許為 null Dictionary 線程安全
ConcurrentHashMap 不允許為 null 不允許為 null AbstractMap 鎖分段技術( JDK8:CAS)
TreeMap 不允許為 null 允許為 null AbstractMap 線程不安全
HashMap 允許為 null 允許為 null AbstractMap 線程不安全
12. 【參考】利用 Set 元素唯一的特性,可以快速對一個集合進行去重操作,避免使用 List 的 contains 方法進行遍歷、對比、 去重操作。
?
?
?