讀阿里Java開發手冊有感

語言: CN / TW / HK

highlight: ascetic theme: condensed-night-purple


前言

都說程式碼不是寫給自己看的,而是寫給其他人看的,大家都能看懂的程式碼才是好程式碼!可是怎樣的程式碼大家才能看懂呢?阿里作為國內Java當之無愧的大佬,最近兩天抽空斷斷續續讀完了阿里的《Java開發手冊》,書中制定了很多規範也提出了很多建議。我想我們每個Javaer在正式開始寫程式碼前都去看看。

其中有一些規範是之前就已經瞭解過的,也有一些是直接依靠現在的ide就可以直接避免的(程式碼規範問題),因此我在這裡就分享一些我之前沒有接觸過的,比較陌生的一些知識。

一.編碼規約

1.1 命名風格

1.程式碼中的命名嚴禁使用拼音和英文結合的方式,全拼音的方式也要避免採用。

2.常量命名全部大寫,單詞之間用下劃線來隔開,力求語義表達清楚,不要嫌名字長。

正例:MAX_STOCK_COUNT
反例:MAX_COUNT

3.抽象類命名使用Abstract或者Base開頭,異常類命名使用Exception結尾,測試類要使用測試的類名開頭,Test結尾。

4.POJO類中boolean型別的變數,都不要加is,否則部分框架解析會引起序列化的錯誤。

反例:定義基本資料型別Boolean isDeleteed;的屬性,它的方法也是isDeleted(),RPC框架在反向解析的時候,以為對應的屬性名稱是deletedd,導致屬性獲取不到,進而丟擲異常。

5.包名統一使用小寫,單數形式,類名可以使用複數形式。

6.如果使用到了設計模式,建議在類名中體現出設計模式。有利於閱讀者快速理解架構設計思想。

例:public class OrderFactory

  1. 獲取單個物件方法用get做字首;獲取多個物件的方法用list做字首;獲取統計值的方法用count做字首;插入的方法用save做字首;刪除的方法用remove做字首,修改的方法用update做字首

1.2 常量定義

1.不允許任何魔法值(未經定義的常量)直接出現在程式碼中。

2.long或者Long賦初值時,必須使用大寫的L,不能使用小寫的l,不容易區分。

3.如果一個常量值僅在一個範圍內變化,且帶有名稱之外的延展屬性,定義為列舉類。

4.所有相同型別的包裝類之間物件值的比較,全部使用equals方法比較。

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

5.所有pojo的屬性必須使用包裝型別,區域性變數使用基本資料型別。

1.3集合處理

1.使用集合轉陣列的方法,必須使用集合的toArray(T[] array),傳入的是型別完全一樣的陣列,大小就是list.size()。

正例:
List list = new ArrayList(2);
list.add("guan");
list.add("bao");
String[] array = new String[list.size()];
array = list.toArray(array);

2.不要在foreach迴圈中進行remove/add操作。remove元素請使用Iterator方式,併發操作需要對Iterator進行加鎖。

3.每個集合初始化時必須要指定集合初始值的大小,否則頻繁擴容非常影響效能。

4.使用entrySet來遍歷map,而不是keySet來遍歷。entryset一次遍歷出所有的key和value。

1.4併發處理

1.所有的執行緒必須通過執行緒池來進行建立,不要使用Executors去建立,而是通過ThreadPoolExecutor的方式,這樣更能充分明白執行緒池的執行規則,規避風險。

2.高併發時同步呼叫應該去考慮鎖的效能損耗,能用無鎖資料結構,就不要用鎖,能鎖區塊就不要鎖方法題,能用物件鎖就不要用類鎖。

3.併發修改統一記錄時,避免更新丟失,需要加鎖,要麼在應用層枷鎖,要麼在快取加鎖,要麼在資料庫層使用樂觀鎖,用version作為版本更新依據。

  1. 對於一寫多讀的變數,可以使用volatile來解決變數同步的問題。

5.ThreadLocal物件無法解決共享物件的更新問題。 建議使用static修飾,這樣只分配一塊儲存空間,所有此類的物件都可以操作這個變數。

1.5 控制語句

1.表達異常分支時,少用if-else方式表達邏輯,可以改用多個if判斷。

2.try-catch的範圍要儘可能的小。

1.6 註釋規約

1.所有抽象類和介面中的方法必須有完整的註釋。

二.資料庫

1.表達是與否概念的欄位,必須使用is_deleted的方式命名,資料型別時unsigned tinyint。

2.主鍵索引名為pk_欄位名;唯一索引名為uk_欄位名;普通索引名為idx_欄位名(id是index簡稱)。

3.小數型別為decimal型別,禁止使用float和double。

4.表必備的三個欄位:id,gmt_creat,gmt_modified。id的型別為bigint。

5.為了提高查詢效率,欄位能夠適當冗餘,但是必須要考慮資料一直,冗餘欄位應遵循不是頻繁修改的欄位,不是varchar超長欄位,更不能是text欄位。

三.工程結構

1. 應用分層

image.png
開放介面層:可直接封裝 Service 方法暴露成 RPC 介面; 通過 Web 封裝成 http 介面; 進行 閘道器安全控制、 流量控制等。

但是我個人覺得更好的是應該將介面層和實現層分離開,只提供接口出去。具體的業務邏輯在介面實現類中完成。也就是將開放介面層分為兩層:開放介面層,開放介面實現類層。
Web 層:主要是對訪問控制進行轉發,各類基本引數校驗,或者不復用的業務簡單處理等。
Service 層:相對具體的業務邏輯服務層。
Manager 層:通用業務處理層,它有如下特徵:
1) 對第三方平臺封裝的層,預處理返回結果及轉化異常資訊;
2) 對 Service 層通用能力的下沉,如快取方案、 中 間件通用處理;
3) 與 DAO 層互動,對多個 DAO 的組合複用。

DAO 層:資料訪問層,與底層 MySQL、 Oracle、 Hbase 進行資料互動。

外部介面或第三方平臺:包括其它部門 RPC 開放介面,基礎平臺,其它公司的 HTTP 介面。

四. 安全規約

1.使用者傳入的所有引數必須做有效性驗證。
2.表單,ajax提交必須執行csrf安全過濾。
3.隸屬於使用者個人頁面或者功能必須進行許可權控制校驗。

五.總結

在開發手冊中不僅定義了程式碼編寫上的規範,其實也給我們避免了很多開發上的小坑!這對於我們的開發無疑是大大有幫助的。

借用書中的一句話:

很多程式設計方式客觀上沒有對錯之分,一致性很重要,可讀性很重要,團隊溝通效率很重要。程式設計師天生需要團隊協作,而協作的正能量要放在問題的有效溝通上。個性化應儘量表現在系統架構和演算法效率的提升上,而不是在合作規範上進行糾纏不休的討論、爭論,最後沒有結論。