代碼規範 阿里開發手冊筆記

不允許任何魔法值直接出現在代碼裏

Objects 工具類

所有的相同類型的包裝類對象之間的值得比較,全部使用equals方法比較

對於 Integer var = ? 在-128 至 127 範圍內的賦值,Integer 對象是在
IntegerCache.cache 產生,會複用已有對象,這個區間內的 Integer 值可以直接使用==進行
判斷,但是這個區間之外的所有數據,都會在堆上產生,並不會複用已有對象,這是一個大坑,
推薦使用 equals 方法進行判斷。

工具類不允許有 public 或 default 構造方法。說明:任何類、方法、參數、變量,嚴控訪問範圍。過於寬泛的訪問範圍,不利於模塊解耦。
思考:如果是一個 private 的方法,想刪除就刪除,可是一個 public 的 service 方法,或者
一個 public 的成員變量,刪除一下,不得手心冒點汗嗎?變量像自己的小孩,儘量在自己的
視線內,變量作用域太大,無限制的到處跑,那麼你會擔心的。

如果自定義對象做爲 Map 的鍵,那麼必須重寫 hashCode 和 equals

使用集合轉數組的方法,必須使用集合的 toArray(T[] array),傳入的是類型完全
一樣的數組,大小就是 list.size()。
String[] sids = sList.toArray(new String[sList.size()]);
說明:java中的強制類型轉換隻是針對單個對象的,想要偷懶將整個數組強轉換成另外一種類型的數組是不行的,這和數組初始化時需要一個個來也是類似的

使用工具類 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)也會隨之修改。

不要在 foreach 循環裏進行元素的 remove/add 操作。remove 元素請使用 Iterator
方式,如果併發操作,需要對 Iterator 對象加鎖。
正例:
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
if (刪除元素的條件) {
iterator.remove();
}
}
反例:
List list = new ArrayList();
list.add(“1”);
list.add(“2”);
for (String item : list) {
if (“1”.equals(item)) {
list.remove(item);
}
}

使用 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 值組合集合。

if()判斷中有很多邏輯的時候應該單獨拿出來寫
final boolean existed = (file.open(fileName, “w”) != null) && (…) || (…);
if (existed) {

}

接口入參保護,這種場景常見的是用於做批量操作的接口。

下列情形,需要進行參數校驗:
1) 調用頻次低的方法。
2) 執行時間開銷很大的方法。此情形中,參數校驗時間幾乎可以忽略不計,但如果因爲參
數錯誤導致中間執行回退,或者錯誤,那得不償失。
3) 需要極高穩定性和可用性的方法。
4) 對外提供的開放接口,不管是 RPC/API/HTTP 接口。
5) 敏感權限入口。

下列情形,不需要進行參數校驗:
1) 極有可能被循環調用的方法。但在方法說明裏必須註明外部參數檢查要求。
2) 底層調用頻度比較高的方法。畢竟是像純淨水過濾的最後一道,參數錯誤不太可能到底
層纔會暴露問題。一般 DAO 層與 Service 層都在同一個應用中,部署在同一臺服務器中,所
以 DAO 的參數校驗,可以省略。
3) 被聲明成 private 只會被自己代碼所調用的方法,如果能夠確定調用方法的代碼傳入參
數已經做過檢查或者肯定不會有問題,此時可以不校驗參數。

謹慎註釋掉代碼。在上方詳細說明,而不是簡單地註釋掉。如果無用,則刪除。
說明:代碼被註釋掉有兩種可能性:1)後續會恢復此段代碼邏輯。2)永久不用。前者如果沒
有備註信息,難以知曉註釋動機。後者建議直接刪掉(代碼倉庫保存了歷史代碼)。

在使用正則表達式時,利用好其預編譯功能,可以有效加快正則匹配速度。
說明:不要在方法體內定義:Pattern pattern = Pattern.compile(規則);

Pattern要定義爲static final靜態變量,以避免執行多次預編譯。

private static final Pattern pattern = Pattern.compile(regexRule);

private void func(…) {
Matcher m = pattern.matcher(content);
if (m.matches()) {

}

及時清理不再使用的代碼段或配置信息。
說明:對於垃圾代碼或過時配置,堅決清理乾淨,避免程序過度臃腫,代碼冗餘。
正例:對於暫時被註釋掉,後續可能恢復使用的代碼片斷,在註釋代碼上方,統一規定使用三
個斜槓(///)來說明註釋掉代碼的理由。

如果非得使用 if()…else if()…else…方式表達邏輯,【強制】避免後續代碼維
護困難,請勿超過 3 層。
正例:超過 3 層的 if-else 的邏輯判斷代碼可以使用衛語句、策略模式、狀態模式等來實現,
其中衛語句示例如下:
public void today() {
if (isBusy()) {
System.out.println(“change time.”);
return;
}
if (isFree()) {
System.out.println(“go to travel.”);
return;
}
System.out.println(“stay at home to learn Alibaba Java Coding Guidelines.”);
return;
}

【強制】異常不要用來做流程控制,條件控制,因爲異常的處理效率比條件分支低。

finally 塊必須對資源對象、流對象進行關閉,有異常也要做 try-catch。
說明:如果 JDK7 及以上,可以使用 try-with-resources 方式。

【強制】用戶請求傳入的任何參數必須做有效性驗證。
說明:忽略參數校驗可能導致:
? page size 過大導致內存溢出
? 惡意 order by 導致數據庫慢查詢
? 任意重定向
? SQL 注入
? 反序列化注入
? 正則輸入源串拒絕服務 ReDoS
說明:Java 代碼用正則來驗證客戶端的輸入,有些正則寫法驗證普通用戶輸入沒有問題,
但是如果攻擊人員使用的是特殊構造的字符串來驗證,有可能導致死循環的結果。

varchar 是可變長字符串,不預先分配存儲空間,長度不要超過 5000,如果存儲長
度大於此值,定義字段類型爲 text,獨立出來一張表,用主鍵來對應,避免影響其它字段索
引效率。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章