阿里巴巴Java開發手冊閱讀筆記

前言

參考:阿里巴巴Java開發手冊V1.3.0java

總結比較重要的,對面試有用的開發規約linux

1、編程規約

(一)命名風格

  • 【強制】POJO 類中布爾類型的變量,都不要加 is,不然部分框架解析會引發序列化錯誤。

反例:定義爲基本數據類型 Boolean isDeleted;的屬性,它的方法也是 isDeleted(),RPC 框架在反向解析的時候,「覺得」對應的屬性名稱是 deleted,致使屬性獲取不到,進而拋出異常。git

  • 【推薦】若是模塊、接口、類、方法使用了設計模式,在命名時體現出具體模式。

public class OrderFactory;程序員

public class LoginProxy;github

public class ResourceObserver;面試

(二)常量定義

  • 【強制】不容許任何魔法值(即未經定義的常量)直接出如今代碼中。

反例:String key = "Id#taobao_" + tradeId;正則表達式

cache.put(key, value);算法

  • 【推薦】若是變量值僅在一個範圍內變化,且帶有名稱以外的延伸屬性,定義爲枚舉類。

正例:public Enum { MONDAY(1), TUESDAY(2), WEDNESDAY(3), THURSDAY(4), FRIDAY(5), SATURDAY(6), SUNDAY(7);}數據庫

(三)代碼格式

(四)OOP 規約

  • 【強制】避免經過一個類的對象引用訪問此類的靜態變量或靜態方法,無謂增長編譯器解析成本,直接用類名來訪問便可。編程

  • 【強制】外部正在調用或者二方庫依賴的接口,不容許修改方法簽名,避免對接口調用方產生影響。接口過期必須加@Deprecated 註解,並清晰地說明採用的新接口或者新服務是什麼。

  • 【強制】全部的相同類型的包裝類對象之間值的比較,所有使用 equals 方法比較。

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

  • 【強制】序列化類新增屬性時,請不要修改 serialVersionUID 字段,避免反序列失敗;若是徹底不兼容升級,避免反序列化混亂,那麼請修改 serialVersionUID 值。

說明:注意 serialVersionUID 不一致會拋出序列化運行時異常。

  • 【強制】構造方法裏面禁止加入任何業務邏輯,若是有初始化邏輯,請放在 init 方法中。

  • 【強制】POJO 類必須寫 toString 方法。使用 IDE 的中工具:source> generate toString 時,若是繼承了另外一個 POJO 類,注意在前面加一下 super.toString。

說明:在方法執行拋出異常時,能夠直接調用 POJO 的 toString()方法打印其屬性值,便於排 查問題。

  • 【推薦】循環體內,字符串的鏈接方式,使用 StringBuilder 的 append 方法進行擴展。

說明:反編譯出的字節碼文件顯示每次循環都會 new 出一個 StringBuilder 對象,而後進行 append 操做,最後經過 toString 方法返回 String 對象,形成內存資源浪費。

反例:

String str = "start";
for (int i = 0; i < 100; i++) {
str = str + "hello";
}
複製代碼

(五)集合處理

  • 【強制】關於 hashCode 和 equals 的處理,遵循以下規則:
    • 1) 只要重寫 equals,就必須重寫 hashCode。
    • 2) 由於 Set 存儲的是不重複的對象,依據 hashCode 和 equals 進行判斷,因此 Set 存儲的對象必須重寫這兩個方法。
    • 3) 若是自定義對象作爲 Map 的鍵,那麼必須重寫 hashCode 和 equals。

說明:String 重寫了 hashCode 和 equals 方法,因此咱們能夠很是愉快地使用 String 對象 做爲 key 來使用。

  • 【強制】ArrayList的subList結果不可強轉成ArrayList,不然會拋出ClassCastException 異常,即 java.util.RandomAccessSubList cannot be cast to java.util.ArrayList.

說明:subList 返回的是 ArrayList 的內部類 SubList,並非 ArrayList ,而是 ArrayList 的一個視圖,對於 SubList 子列表的全部操做最終會反映到原列表上。

  • 【強制】使用集合轉數組的方法,必須使用集合的 toArray(T[] array),傳入的是類型徹底同樣的數組,大小就是 list.size()。

反例:直接使用 toArray 無參方法存在問題,此方法返回值只能是 Object[]類,若強轉其它 類型數組將出現 ClassCastException 錯誤。

  • 【強制】使用工具類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 對象加鎖。

  • 【推薦】高度注意 Map 類集合 K/V 能不能存儲 null 值的狀況,以下表格:

在這裏插入圖片描述

(六)併發處理

  • 【強制】線程資源必須經過線程池提供,不容許在應用中自行顯式建立線程。

說明:使用線程池的好處是減小在建立和銷燬線程上所花的時間以及系統資源的開銷,解決資 源不足的問題。若是不使用線程池,有可能形成系統建立大量同類線程而致使消耗完內存或者 「過分切換」的問題。

  • 【強制】線程池不容許使用 Executors 去建立,而是經過 ThreadPoolExecutor 的方式,這樣的處理方式讓寫的同窗更加明確線程池的運行規則,規避資源耗盡的風險。

  • 【推薦】避免 Random 實例被多線程使用,雖然共享該實例是線程安全的,但會因競爭同一seed 致使的性能降低。

說明:Random 實例包括 java.util.Random 的實例或者 Math.random()的方式。

正例:在 JDK7 以後,能夠直接使用 API ThreadLocalRandom,而在 JDK7 以前,須要編碼保 證每一個線程持有一個實例。

  • 【參考】volatile 解決多線程內存不可見問題。對於一寫多讀,是能夠解決變量同步問題,可是若是多寫,一樣沒法解決線程安全問題。若是是count++操做,使用以下類實現:AtomicInteger count = new AtomicInteger(); count.addAndGet(1); 若是是 JDK8,推薦使用 LongAdder 對象,比 AtomicLong 性能更好(減小樂觀鎖的重試次數)。

(七)控制語句

  • 【推薦】表達異常的分支時,少用 if-else 方式

說明:若是非得使用 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;
}
複製代碼

(八)註釋規約

(九)其它

  • 【強制】在使用正則表達式時,利用好其預編譯功能,能夠有效加快正則匹配速度。

  • 【強制】後臺輸送給頁面的變量必須加$!{var}——中間的感嘆號。

說明:若是 var=null 或者不存在,那麼${var}會直接顯示在頁面上。

  • 【強制】注意 Math.random() 這個方法返回是 double 類型,注意取值的範圍 0≤x<1(可以 取到零值,注意除零異常),若是想獲取整數類型的隨機數,不要將 x 放大 10 的若干倍而後 取整,直接使用 Random 對象的 nextInt 或者 nextLong 方法。

2、異常日誌

(一)異常處理

  • 【強制】Java 類庫中定義的一類 RuntimeException 能夠經過預先檢查進行規避,而不該該 經過 catch 來處理,好比:IndexOutOfBoundsException,NullPointerException 等等。

正例:if (obj != null) {...}

反例:try { obj.method() } catch (NullPointerException e) {...}

  • 【強制】異常不要用來作流程控制,條件控制,由於異常的處理效率比條件分支低。

  • 【強制】對大段代碼進行 try-catch,這是不負責任的表現

  • 【強制】捕獲異常是爲了處理它,不要捕獲了卻什麼都不處理而拋棄之,若是不想處理它,請 將該異常拋給它的調用者。最外層的業務使用者,必須處理異常,將其轉化爲用戶能夠理解的 內容。

  • 【推薦】防止 NPE,是程序員的基本修養.

  • 【參考】在代碼中使用「拋異常」仍是「返回錯誤碼」,對於公司外的 http/api 開放接口必須 使用「錯誤碼」;而應用內部推薦異常拋出;跨應用間 RPC 調用優先考慮使用 Result 方式,封 裝 isSuccess()方法、「錯誤碼」、「錯誤簡短信息」

(二)日誌規約

  • 【強制】日誌文件推薦至少保存 15 天,由於有些異常具有以「周」爲頻次發生的特色。

  • 【強制】應用中不可直接使用日誌系統(Log4j、Logback)中的 API,而應依賴使用日誌框架SLF4J中的API,使用門面模式的日誌框架,有利於維護和各個類的日誌處理方式統一。

3、單元測試

  • 【強制】好的單元測試必須遵照 AIR 原則。 說明:單元測試在線上運行時,感受像空氣(AIR)同樣並不存在,但在測試質量的保障上, 倒是很是關鍵的。好的單元測試宏觀上來講,具備自動化、獨立性、可重複執行的特色。
    • A:Automatic(自動化)
    • I:Independent(獨立性)
    • R:Repeatable(可重複)

4、安全規約

  • 【強制】隸屬於用戶我的的頁面或者功能必須進行權限控制校驗。

  • 【強制】用戶輸入的 SQL 參數嚴格使用參數綁定或者 METADATA 字段值限定,防止 SQL 注入, 禁止字符串拼接 SQL 訪問數據庫。

  • 【強制】用戶請求傳入的任何參數必須作有效性驗證。

5、MySQL 數據庫

(一) 建表規約

  • 【強制】若是存儲的字符串長度幾乎相等,使用 char 定長字符串類型。

  • 【強制】表達是與否概念的字段,必須使用 is _ xxx 的方式命名,數據類型是 unsigned tinyint( 1 表示是,0 表示否 )

    • 說明:任何字段若是爲非負數,必須是 unsigned 。
    • 正例:表達邏輯刪除的字段名 is_deleted ,1 表示刪除,0 表示未刪除。
  • 【強制】 varchar 是可變長字符串,不預先分配存儲空間,長度不要超過 5000,若是存儲長 度大於此值,定義字段類型爲 text ,獨立出來一張表,用主鍵來對應,避免影響其它字段索 引效率。

  • 【強制】表必備三字段: id , gmt _ create , gmt _ modified 。

    • 說明:其中 id 必爲主鍵,類型爲 unsigned bigint 、單表時自增、步長爲 1。 gmt_create, gmt_modified 的類型均爲 date_time 類型,前者如今時表示主動建立,後者過去分詞表示被 動更新。
  • 【推薦】字段容許適當冗餘,以提升查詢性能,但必須考慮數據一致。冗餘字段應遵循:

    • 1 ) 不是頻繁修改的字段。
    • 2 ) 不是 varchar 超長字段,更不能是 text 字段。
    • 正例:商品類目名稱使用頻率高,字段長度短,名稱基本一成不變,可在相關聯的表中冗餘存 儲類目名稱,避免關聯查詢。

(二) 索引規約

  • 【強制】業務上具備惟一特性的字段,即便是多個字段的組合,也必須建成惟一索引。

  • 【強制】超過三個表禁止 join。須要 join 的字段,數據類型必須絕對一致;多表關聯查詢時, 保證被關聯的字段須要有索引。

  • 【強制】在 varchar 字段上創建索引時,必須指定索引長度,不必對全字段創建索引,根據 實際文本區分度決定索引長度便可。

  • 【強制】頁面搜索嚴禁左模糊或者全模糊,若是須要請走搜索引擎來解決。

  • 【推薦】利用覆蓋索引來進行查詢操做,避免回表。說明:若是一本書須要知道第 11 章是什麼標題,會翻開第 11 章對應的那一頁嗎?目錄瀏覽 一下就好,這個目錄就是起到覆蓋索引的做用。

正例:可以創建索引的種類:主鍵索引、惟一索引、普通索引,而覆蓋索引是一種查詢的一種 效果,用 explain 的結果,extra 列會出現:using index。

  • 【推薦】建組合索引的時候,區分度最高的在最左邊。

正例:若是 where a=? and b=? ,a 列的幾乎接近於惟一值,那麼只須要單建 idx_a 索引即 可。

(三) SQL語句

  • 【強制】不要使用 count(列名)或 count(常量)來替代 count(*),count(*)是 SQL92 定義的 標準統計行數的語法,跟數據庫無關,跟 NULL 和非 NULL 無關。

  • 【強制】不得使用外鍵與級聯,一切外鍵概念必須在應用層解決。

    • 說明:以學生和成績的關係爲例,學生表中的 student _ id 是主鍵,那麼成績表中的 student _ id則爲外鍵。若是更新學生表中的 student _ id ,同時觸發成績表中的 student _ id 更新,即爲級聯更新。外鍵與級聯更新適用於單機低併發,不適合分佈式、高併發集羣 ; 級聯更新是強阻塞,存在數據庫更新風暴的風險 ; 外鍵影響數據庫的插入速度。
  • 【強制】禁止使用存儲過程,存儲過程難以調試和擴展,更沒有移植性。

(四)ORM 映射

  • 【強制】在表查詢中,一概不要使用 * 做爲查詢的字段列表,須要哪些字段必須明確寫明。

6、工程結構

(一)應用分層

在這裏插入圖片描述

(二)二方庫依賴

(三)服務器

  • 【推薦】高併發服務器建議調小 TCP 協議的 time_ wait 超時時間。

    • 說明:操做系統默認 240 秒後,纔會關閉處於 time_ wait 狀態的鏈接,在高併發訪問下,服務器端會由於處於 time _ wait的鏈接數太多,可能沒法創建新的鏈接,因此須要在服務器上調小此等待值。
    • 正例:在 linux 服務器上請經過變動/ etc / sysctl . conf 文件去修改該缺省值 ( 秒 ) : net . ipv 4. tcp _ fin _ timeout = 30
  • 【推薦】調大服務器所支持的最大文件句柄數 (File Descriptor ,簡寫爲 fd) 。

    • 說明:主流操做系統的設計是將 TCP / UDP 鏈接採用與文件同樣的方式去管理,即一個鏈接對 應於一個 fd 。主流的 linux 服務器默認所支持最大 fd 數量爲 1024,當併發鏈接數很大時很 容易由於 fd 不足而出現「 open too many files 」錯誤,致使新的鏈接沒法創建。 建議將 linux 服務器所支持的最大句柄數調高數倍 ( 與服務器的內存數量相關 ) 。
  • 【推薦】給 JVM 設置-XX:+HeapDumpOnOutOfMemoryError 參數,讓 JVM 碰到 OOM 場景時輸出 dump 信息。

  • 【推薦】在線上生產環境, JVM 的 Xms 和 Xmx 設置同樣大小的內存容量,避免在 GC 後調整堆 大小帶來的壓力。

  • 【參考】服務器內部重定向使用 forward; 外部重定向地址使用 URL 拼裝工具類來生成,不然 會帶來 URL 維護不一致的問題和潛在的安全風險。

關注我

我是蠻三刀把刀,目前爲後臺開發工程師。主要關注後臺開發,網絡安全,Python爬蟲等技術。

來微信和我聊聊:yangzd1102

Github:github.com/qqxx6661

原創博客主要內容

  • 筆試面試複習知識點手冊
  • Leetcode算法題解析(前150題)
  • 劍指offer算法題解析
  • Python爬蟲相關技術分析和實戰
  • 後臺開發相關技術分析和實戰

我的公衆號:Rude3Knife

我的公衆號:Rude3Knife

若是文章對你有幫助,不妨收藏起來並轉發給您的朋友們~

相關文章
相關標籤/搜索