2016年末的時候阿里巴巴公開了其在內部使用的Java編程規範。隨後進行了幾回版本修訂,目前的版本爲v1.0.2版。下載地址能夠在其官方社區-雲棲社區https://yq.aliyun.com/articles/69327找到。css
筆者做爲一名有數年工做經驗的Java程序員,仔細研讀了這份手冊,以爲其是一份不可多得的好材料。阿里巴巴在發佈時所說,「阿里巴巴集團推出的《阿里巴巴Java開發手冊(正式版)》是阿里巴巴近萬名開發同窗集體智慧的結晶,以開發視角爲中心,詳細列舉如何開發更加高效、更加容錯、更加有協做性,力求知其然,更知其否則,結合正反例,讓Java開發者可以提高協做效率、提升代碼質量。」 同時,阿里巴巴也指望這套Java統一規範標準將有助於提升行業編碼規範化水平,幫助行業人員提升開發質量和效率、大大下降代碼維護成本。html
其實早在多年前,Google就已經把公司內部採用的全部語言的編碼規範(其稱爲Style Guide)都開源在github上,地址爲https://github.com/google/styleguide。在這份清單中,包括了C++、Objective-C、Java、Python、R、Shell、HTML/CSS、JavaScript、AngularJS、Common Lisp、Vimscript等語言的編程規範。而且Google還發布了一個用於檢查樣式合規性的工具cpplint以及Emacs中使用Google編程樣式的配置文件google-c-style.el。看來Google中Emacs粉比Vim粉要強勢的多。java
Google爲何要發佈這樣的Style Guide那?由於它認爲幾乎全部的開源項目都須要有一組約定來規範如何編寫代碼。若是項目中的代碼都能保持一致的風格,那麼即便代碼再多也會更容易被人理解。git
Google的這份編程規範包含了不少方面,從」對變量使用camelCase命名法」到」毫不要使用全局變量」到」毫不容許例外「等。其Java編程規範包含7大部分,分別爲介紹、源文件基本要求、源文件結構、格式化、命名、編程實踐和Javadoc。每一部分又細分爲不少子條目。若是採起條規範的緣由不是很容易理解,都會配有相應的示例或者引用文章。程序員
因爲Google的這份編程規範目前只有英文版本,因此中國的程序員只有少部分人知道它的存在。而且只有更少的團隊在真正的應用它,其中就包括個人團隊。咱們團隊根據Google的Java style guide也演化出了本身的團隊版本,放置在團隊共享wiki上供你們隨時查閱。咱們根據自身的項目特色豐富了」編程實踐」裏的內容,而且新加入一個章節來描述編寫Java代碼的一些原則,好比簡潔代碼、組合優於繼承、stream優於for循環等。angularjs
我想阿里巴巴發佈的Java開發手冊之因此叫作」開發手冊」,而不是像Google那樣叫作「Style Guide(樣式風格)」,是由於它不只僅侷限於style guide這一方面,而是以Java開發者爲中心視角,劃分爲編程規約、異常日誌規約、MYSQL規約、工程規約、安全規約五大塊,再根據內容特徵,細分紅若干二級子目錄。根據約束力強弱和故障敏感性,規約依次分爲強制、推薦、參考三大類。github
該開發手冊中的每一條都值得了解。限於篇幅緣由,這裏只列出」編程規約「中有感覺的幾條來評述一下。面試
15. 【參考】各層命名規約:shell
A) Service/DAO 層方法命名規約編程
1) 獲取單個對象的方法用 get 作前綴。
2) 獲取多個對象的方法用 list 作前綴。
3) 獲取統計值的方法用 count 作前綴。
4) 插入的方法用 save(推薦)或 insert 作前綴。
5) 刪除的方法用 remove(推薦)或 delete 作前綴。
6) 修改的方法用 update 作前綴。
B) 領域模型命名規約
1) 數據對象:xxxDO,xxx 即爲數據表名。
2) 數據傳輸對象:xxxDTO,xxx 爲業務領域相關的名稱。
3) 展現對象:xxxVO,xxx 通常爲網頁名稱。
4) POJO 是 DO/DTO/BO/VO 的統稱,禁止命名成 xxxPOJO。
命名規約的第15條描述了在Service/DAO層對於資源的操做的命名規範。這一條的參考價值極大,由於我全部呆過的團隊對於這一點都沒有明顯的約束,每一個團隊都有五花八門的實現。若是能遵照這一點,那麼咱們在操做資源時就會減小一些困擾。
2. 【強制】long 或者 Long 初始賦值時,必須使用大寫的 L,不能是小寫的 l,小寫容易跟數字1混淆,形成誤解。
說明:Long a = 2l; 寫的是數字的 21,仍是 Long 型的 2?
這是常量定義的第2條。從這一點能夠看出阿里巴巴對代碼可讀性的細節扣的很嚴格。我也很贊同這一點。代碼只需編寫一次,而會被查看無數次,因此要力爭在第一次編寫的時候儘量少的引入歧義。
1. 【強制】大括號的使用約定。若是是大括號內爲空,則簡潔地寫成{}便可,不須要換行;若是是非空代碼塊則:
1) 左大括號前不換行。
2) 左大括號後換行。
3) 右大括號前換行。
4) 右大括號後還有 else 等代碼則不換行;表示終止右大括號後必須換行。
格式規約的第1條終於終結了括號之爭。這一條須要強制遵照,那麼左大括號換行一派則被完全排除在阿里巴巴以外。有人說不推薦左大括號換行能夠減小行數,增長單個屏幕能夠顯示的代碼行數。而有的人反駁說如今屏幕已經足夠大,不換行則破壞了對稱之美。其實對於我來講兩種格式都有各自的好處,我均可以接受,只要團隊可以堅持使用其中之一便可。
5. 【強制】縮進採用 4 個空格,禁止使用 tab 字符。
說明:若是使用 tab 縮進,必須設置 1 個 tab 爲 4 個空格。IDEA 設置 tab 爲 4 個空格時,請勿勾選 Use tab character;而在 eclipse 中,必須勾選 insert spaces for tabs。
正例: (涉及 1-5 點)
public static void main(String[] args) { // 縮進 4 個空格 String say = "hello"; // 運算符的左右必須有一個空格 int flag = 0; // 關鍵詞 if 與括號之間必須有一個空格,括號內的 f 與左括號,0 與右括號不須要空格 if (flag == 0) { System.out.println(say); } // 左大括號前加空格且不換行;左大括號後換行 if (flag == 1) { System.out.println("world"); // 右大括號前換行,右大括號後有 else,不用換行 } else { System.out.println("ok"); // 在右大括號後直接結束,則必須換行 } }
使用空格代替tab字符進行縮進已經成爲了編程界的共識。其主要緣由是不一樣的平臺甚至不一樣的編輯器下tab字符的長短是不同的。不過Google在其《java style guide》中規定縮進爲2個空格,而阿里巴巴約定爲4個空格。因爲4個空格的縮進比2個空格的縮進長一倍,因此若是在代碼嵌套過深的狀況下可能會很快超過單行最多字符數(阿里巴巴規定爲120個)的限制。不過這個問題能夠從另外一個方面進行思考,若是因爲縮進的緣由致使單行字符數超標,這極可能是代碼設計上有壞味道而致使嵌套過深。因此最好應該從調整代碼結構的方面下手。
6. 【強制】單行字符數限制不超過 120 個,超出須要換行,換行時遵循以下原則:
1) 第二行相對第一行縮進 4 個空格,從第三行開始,再也不繼續縮進,參考示例。
2) 運算符與下文一塊兒換行。
3) 方法調用的點符號與下文一塊兒換行。
4) 在多個參數超長,逗號後進行換行。
5) 在括號前不要換行,見反例。
正例:
StringBuffer sb = new StringBuffer(); //超過 120 個字符的狀況下,換行縮進 4 個空格,而且方法前的點符號一塊兒換行 sb.append("zi").append("xin")... .append("huang")... .append("huang")... .append("huang");反例:
StringBuffer sb = new StringBuffer(); //超過 120 個字符的狀況下,不要在括號前換行 sb.append("zi").append("xin")...append ("huang"); //參數不少的方法調用可能超過 120 個字符,不要在逗號前換行 method(args1, args2, args3, ... , argsX);
關於換行Google並無給出明確的要求,而阿里巴巴則給出了強制性的要求。Google特別提示經過一些重構手法能夠減小單行字符長度從而避免換行,這一點我頗爲認同。關於參數不少的方法調用超過120個字符須要換行時,這暴露除了過長參數列的代碼壞味道,解決方式之一就是使用重構手法的Replace Parameter With Method的方式把一次方法調用化爲屢次方法調用,或者使用Introduce Parameter Object手法創造出參數對象並進行傳遞。
17. 【推薦】循環體內,字符串的聯接方式,使用 StringBuilder 的 append 方法進行擴展。 反例:
String str = "start"; for (int i = 0; i < 100; i++) { str = str + "hello"; }說明:反編譯出的字節碼文件顯示每次循環都會 new 出一個 StringBuilder 對象,而後進行append 操做,最後經過 toString 方法返回 String 對象,形成內存資源浪費。
這是《Effective Java》以及其餘文章中常常說起的優化方式,並且面試初級Java工程師時幾乎是一個必考點。其實不只是在循環體內,而是全部須要進行屢次字符串拼接的地方都應該使用StringBuilder對象。
20. 【推薦】類成員與方法訪問控制從嚴:
1) 若是不容許外部直接經過 new 來建立對象,那麼構造方法必須是 private。
2) 工具類不容許有 public 或 default 構造方法。
3) 類非 static 成員變量而且與子類共享,必須是 protected。
4) 類非 static 成員變量而且僅在本類使用,必須是 private。
5) 類 static 成員變量若是僅在本類使用,必須是 private。
6) 如果 static 成員變量,必須考慮是否爲 final。
7) 類成員方法只供類內部調用,必須是 private。
8) 類成員方法只對繼承類公開,那麼限制爲 protected。
說明:任何類、方法、參數、變量,嚴控訪問範圍。過寬泛的訪問範圍,不利於模塊解耦。思 考:若是是一個 private 的方法,想刪除就刪除,但是一個 public 的 Service 方法,或者一個 public 的成員變量,刪除一下,不得手心冒點汗嗎?變量像本身的小孩,儘可能在本身的視線內,變量做用域太大,若是無限制的處處跑,那麼你會擔憂的。
這其實就是經典的原則‘ Principle of least privilege’ 的體現。咱們必須遵循這一原則,但不知爲什麼阿里巴巴將其級別列爲「推薦」。
7. 【參考】方法中須要進行參數校驗的場景:
1) 調用頻次低的方法。
2) 執行時間開銷很大的方法,參數校驗時間幾乎能夠忽略不計,但若是由於參數錯誤致使 中間執行回退,或者錯誤,那得不償失。
3) 須要極高穩定性和可用性的方法。
4) 對外ᨀ供的開放接口,無論是 RPC/API/HTTP 接口。
5) 敏感權限入口。
8. 【參考】方法中不須要參數校驗的場景:
1) 極有可能被循環調用的方法,不建議對參數進行校驗。但在方法說明裏必須註明外部參 數檢查。
2) 底層的方法調用頻度都比較高,通常不校驗。畢竟是像純淨水過濾的最後一道,參數錯 誤不太可能到底層纔會暴露問題。通常 DAO 層與 Service 層都在同一個應用中,部署在同一 臺服務器中,因此 DAO 的參數校驗,能夠省略。
3) 被聲明成 private 只會被本身代碼所調用的方法,若是可以肯定調用方法的代碼傳入參 數已經作過檢查或者確定不會有問題,此時能夠不校驗參數。
編寫代碼時,對參數進行校驗是不可避免的。詳細說又扯到「防護式編程」和「契約式編程」的話題上。這兩項之因此列爲參考,並無強迫你們遵照。
6. 【推薦】與其「半吊子」英文來註釋,不如用中文註釋把問題說清楚。專有名詞與關鍵字保持英文原文便可。
反例:「TCP 鏈接超時」解釋成「傳輸控制協議鏈接超時」,理解反而費腦筋。
看到這一條我已經笑出來了。這一條說的很好,註釋是用來闡述問題的,若是看了註釋還一頭霧水,那麼這樣的註釋不要也罷。使用中文沒什麼可丟人的,解決問題纔是王道。
7. 【推薦】代碼修改的同時,註釋也要進行相應的修改,尤爲是參數、返回值、異常、核心邏輯等的修改。
說明:代碼與註釋更新不一樣步,就像路網與導航軟件更新不一樣步同樣,若是導航軟件嚴重滯後, 就失去了導航的意義。
阿里巴巴對該條的說明很是到位。其實咱們團隊在編寫代碼時默認是沒有任何註釋的,由於咱們追求的是self-explanatory methods。即代碼自己已經就能說明它的用途。只有在不多的狀況下須要添加註釋。
編程規約的第九部分都是很好的tips,值得去了解和學習。
除了編程規約以外,日誌規約、MySQL規約、工程規約和安全規約也都有極高的參考價值,這也是比Google的Java Style Guide出色的地方。這裏就再也不評述了。
阿里巴巴公佈這個Java開發手冊絕對是值得讚揚的事情。最後我也想給其提幾點建議:
建議使用公開wiki的方式發佈該手冊,而不是採用pdf的方式。由於若是像google那樣是公開wiki的方式的話,能夠很方便你們參與修正和改進,而且能夠看到版本歷史。
該手冊並無明確的版權許可,只是在頁腳處加入了「禁止用於商業用途,違者必究」的字樣。Google的style guide的版權爲CC-By 3.0 License,建議阿里巴巴可以指明其版權。
-
手冊中的部分示例代碼並無遵照其列出的編程規約,有點打臉之嫌。好比如下示例代碼:
Iterator<String> it = a.iterator(); while(it.hasNext()){ String temp = it.next(); if(刪除元素的條件){ it.remove(); } }
其while和if關鍵字與小括號之間並無空格,違反了該手冊中3. 【強制】if/for/while/switch/do 等保留字與左右括號之間都必須加空格。
這一規則。
- 集合處理中能夠多推薦一些Java8的集合操做方法。
- 有些名詞沒有過多解釋,好比不少人可能都不知道什麼叫一方庫、二方庫。
- 但願除了這份開發手冊之外,阿里巴巴也能夠推出對應的checkstyle配置文件以及Intellij、Eclipse的配置文件。畢竟格式化這些事均可以交由IDE來解決,經過在構建時使用checkstyle插件也能夠防止不合規的代碼遷入到倉庫,從源頭上保證代碼樣式的一致性。
最後,但願這份Java開發手冊能夠持續改進,吸納百家之長,成爲每一個入門程序員必看的手冊。