阿里巴巴Java開發手冊--程式碼抒寫規範和注意
Java中 VO、 PO、DO、DTO、 BO、 QO、DAO、POJO的概念
PO(persistant object) 持久物件
在 o/r 對映的時候出現的概念,如果沒有 o/r 對映,沒有這個概念存在了。通常對應資料模型 ( 資料庫 ), 本身還有部分業務邏輯的處理。可以看成是與資料庫中的表相對映的 java 物件。最簡單的 PO 就是對應資料庫中某個表中的一條記錄,多個記錄可以用 PO 的集合。 PO 中應該不包含任何對資料庫的操作。
DO(Domain Object)領域物件
就是從現實世界中抽象出來的有形或無形的業務實體。一般和資料中的表結構對應。
TO(Transfer Object) ,資料傳輸物件
在應用程式不同 tie( 關係 ) 之間傳輸的物件
DTO(Data Transfer Object)資料傳輸物件
這個概念來源於J2EE的設計模式,原來的目的是為了EJB的分散式應用提供粗粒度的資料實體,以減少分散式呼叫的次數,從而提高分散式呼叫的效能和降低網路負載,但在這裡,我泛指用於展示層與服務層之間的資料傳輸物件。
VO(view object) 值物件
檢視物件,用於展示層,它的作用是把某個指定頁面(或元件)的所有資料封裝起來。
BO(business object) 業務物件
從業務模型的角度看 , 見 UML 元件領域模型中的領域物件。封裝業務邏輯的 java 物件 , 通過呼叫 DAO 方法 , 結合 PO,VO 進行業務操作。 business object: 業務物件 主要作用是把業務邏輯封裝為一個物件。這個物件可以包括一個或多個其它的物件。 比如一個簡歷,有教育經歷、工作經歷、社會關係等等。 我們可以把教育經歷對應一個 PO ,工作經歷對應一個 PO ,社會關係對應一個 PO 。 建立一個對應簡歷的 BO 物件處理簡歷,每個 BO 包含這些 PO 。 這樣處理業務邏輯時,我們就可以針對 BO 去處理。
POJO(plain ordinary java object) 簡單無規則 java 物件
純的傳統意義的 java 物件。就是說在一些 Object/Relation Mapping 工具中,能夠做到維護資料庫表記錄的 persisent object 完全是一個符合 Java Bean 規範的純 Java 物件,沒有增加別的屬性和方法。我的理解就是最基本的 Java Bean ,只有屬性欄位及 setter 和 getter 方法!。
DAO(data access object) 資料訪問物件
是一個 sun 的一個標準 j2ee 設計模式, 這個模式中有個介面就是 DAO ,它負持久層的操作。為業務層提供介面。此物件用於訪問資料庫。通常和 PO 結合使用, DAO 中包含了各種資料庫的操作方法。通過它的方法 , 結合 PO 對資料庫進行相關的操作。夾在業務邏輯與資料庫資源中間。配合 VO, 提供資料庫的 CRUD 操作
一、 程式設計規約
(一)命名風格
1. 【強制】 程式碼中的命名均不能以下劃線或美元符號開始,也不能以下劃線或美元符號結束。
反例: _name / __name / $name / name_ / name$ / name__
2. 【強制】 程式碼中的命名嚴禁使用拼音與英文混合的方式,更不允許直接使用中文的方式。
說明: 正確的英文拼寫和語法可以讓閱讀者易於理解,避免歧義。注意,即使純拼音命名方式
也要避免採用。
正例: alibaba / taobao / youku / hangzhou 等國際通用的名稱, 可視同英文。
反例: DaZhePromotion [打折] / getPingfenByName() [評分] / int 某變數 = 3
3. 【強制】類名使用 UpperCamelCase 風格,但以下情形例外: DO / BO / DTO / VO / AO /
PO 等。
正例: MarcoPolo / UserDO / XmlService / TcpUdpDeal / TaPromotion
反例: macroPolo / UserDo / XMLService / TCPUDPDeal / TAPromotion
4. 【強制】方法名、引數名、成員變數、區域性變數都統一使用 lowerCamelCase 風格,必須遵從
駝峰形式。
正例: localValue / getHttpMessage() / inputUserId
5. 【強制】常量命名全部大寫,單詞間用下劃線隔開,力求語義表達完整清楚,不要嫌名字長。
正例: MAX_STOCK_COUNT
反例: MAX_COUNT
6. 【強制】抽象類命名使用 Abstract 或 Base 開頭; 異常類命名使用 Exception 結尾; 測試類
命名以它要測試的類名開始,以 Test 結尾。
7. 【強制】型別與中括號緊挨相連來定義陣列。
正例: 定義整形陣列 int[] arrayDemo;
反例: 在 main 引數中,使用 String args[]來定義。
8. 【強制】POJO 類中布林型別的變數,都不要加 is 字首,否則部分框架解析會引起序列化錯誤。
反例: 定義為基本資料型別 Boolean isDeleted; 的屬性,它的方法也是 isDeleted(), RPC
阿里巴巴 Java 開發手冊
2/36
框架在反向解析的時候, “誤以為” 對應的屬性名稱是 deleted,導致屬性獲取不到,進而拋
出異常。
9. 【強制】包名統一使用小寫,點分隔符之間有且僅有一個自然語義的英語單詞。包名統一使用
單數形式,但是類名如果有複數含義,類名可以使用複數形式。
正例: 應用工具類包名為 com.alibaba.ai.util、類名為 MessageUtils(此規則參考 spring
的框架結構)
10. 【強制】杜絕完全不規範的縮寫, 避免望文不知義。
反例: AbstractClass“縮寫” 命名成 AbsClass; condition“縮寫” 命名成 condi,此類隨
意縮寫嚴重降低了程式碼的可閱讀性。
11. 【推薦】為了達到程式碼自解釋的目標,任何自定義程式設計元素在命名時,使用盡量完整的單詞
組合來表達其意。
正例: 從遠端倉庫拉取程式碼的類命名為 PullCodeFromRemoteRepository。
反例: 變數 int a; 的隨意命名方式。
12. 【推薦】如果模組、 介面、類、方法使用了設計模式,在命名時體現出具體模式。
說明: 將設計模式體現在名字中,有利於閱讀者快速理解架構設計理念。
正例: public class OrderFactory;
public class LoginProxy;
public class ResourceObserver;
13. 【推薦】介面類中的方法和屬性不要加任何修飾符號(public 也不要加) ,保持程式碼的簡潔
性,並加上有效的 Javadoc 註釋。儘量不要在接口裡定義變數,如果一定要定義變數,肯定是
與介面方法相關,並且是整個應用的基礎常量。
正例: 介面方法簽名 void f();
介面基礎常量 String COMPANY = "alibaba";
反例: 介面方法定義 public abstract void f();
說明: JDK8 中介面允許有預設實現,那麼這個 default 方法,是對所有實現類都有價值的默
認實現。
14. 介面和實現類的命名有兩套規則:
1) 【強制】對於 Service 和 DAO 類,基於 SOA 的理念,暴露出來的服務一定是介面,內部
的實現類用 Impl 的字尾與介面區別。
正例: CacheServiceImpl 實現 CacheService 介面。
2)【推薦】 如果是形容能力的介面名稱,取對應的形容詞為介面名(通常是–able 的形式)。
正例: AbstractTranslator 實現 Translatable。
阿里巴巴 Java 開發手冊
3/36
15.【參考】列舉類名建議帶上 Enum 字尾,列舉成員名稱需要全大寫,單詞間用下劃線隔開。
說明: 列舉其實就是特殊的常量類,且構造方法被預設強制是私有。
正例: 列舉名字為 ProcessStatusEnum 的成員名稱: SUCCESS / UNKNOWN_REASON。
16.【參考】各層命名規約:
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。
(二)常量定義
1. 【強制】不允許任何魔法值(即未經預先定義的常量) 直接出現在程式碼中。
反例: String key = "Id#taobao_" + tradeId;
cache.put(key, value);
2. 【強制】 long 或者 Long 初始賦值時, 使用大寫的 L,不能是小寫的 l,小寫容易跟數字 1 混
淆,造成誤解。
說明: Long a = 2l; 寫的是數字的 21,還是 Long 型的 2?
3. 【推薦】不要使用一個常量類維護所有常量, 按常量功能進行歸類,分開維護。
說明: 大而全的常量類,非得使用查詢功能才能定位到修改的常量,不利於理解和維護。
正例: 快取相關常量放在類 CacheConsts 下; 系統配置相關常量放在類 ConfigConsts 下。
4. 【推薦】常量的複用層次有五層:跨應用共享常量、應用內共享常量、子工程內共享常量、包
內共享常量、類內共享常量。
1) 跨應用共享常量:放置在二方庫中,通常是 client.jar 中的 constant 目錄下。
2) 應用內共享常量:放置在一方庫中, 通常是子模組中的 constant 目錄下。
反例: 易懂變數也要統一定義成應用內共享常量,兩位攻城師在兩個類中分別定義了表示
“是”的變數:
類 A 中: public static final String YES = "yes";
阿里巴巴 Java 開發手冊
4/36
類 B 中: public static final String YES = "y";
A.YES.equals(B.YES),預期是 true,但實際返回為 false,導致線上問題。
3) 子工程內部共享常量:即在當前子工程的 constant 目錄下。
4) 包內共享常量:即在當前包下單獨的 constant 目錄下。
5) 類內共享常量:直接在類內部 private static final 定義。
5. 【推薦】 如果變數值僅在一個固定範圍內變化用 enum 型別來定義。
說明: 如果存在名稱之外的延伸屬性使用 enum 型別,下面正例中的數字就是延伸資訊,表示
一年中的第幾個季節。
正例:
public enum SeasonEnum {
SPRING(1), SUMMER(2), AUTUMN(3), WINTER(4);
int seq;
SeasonEnum(int seq){
this.seq = seq;
}
}
(三)程式碼格式
1. 【強制】大括號的使用約定。如果是大括號內為空,則簡潔地寫成{}即可,不需要換行; 如果
是非空程式碼塊則:
1) 左大括號前不換行。
2) 左大括號後換行。
3) 右大括號前換行。
4) 右大括號後還有 else 等程式碼則不換行; 表示終止的右大括號後必須換行。
2. 【強制】 左小括號和字元之間不出現空格; 同樣,右小括號和字元之間也不出現空格。詳見
第 5 條下方正例提示。
反例: if (空格 a == b 空格)
3. 【強制】 if/for/while/switch/do 等保留字與括號之間都必須加空格。
4. 【強制】任何二目、 三目運算子的左右兩邊都需要加一個空格。
說明: 運算子包括賦值運算子=、邏輯運算子&&、加減乘除符號等。
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 個空格
阿里巴巴 Java 開發手冊
5/36
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");
// 在右大括號後直接結束,則必須換行
}
}
6. 【強制】註釋的雙斜線與註釋內容之間有且僅有一個空格。
正例:
// 這是示例註釋,請注意在雙斜線之後有一個空格
String ygb = new String();
7. 【強制】單行字元數限制不超過 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);
8. 【強制】方法引數在定義和傳入時,多個引數逗號後邊必須加空格。
正例: 下例中實參的"a",後邊必須要有一個空格。
method("a", "b", "c");
阿里巴巴 Java 開發手冊
6/36
9. 【強制】 IDE 的 text file encoding 設定為 UTF-8; IDE 中檔案的換行符使用 Unix 格式,
不要使用 Windows 格式。
10. 【推薦】沒有必要增加若干空格來使某一行的字元與上一行對應位置的字元對齊。
正例:
int a = 3;
long b = 4L;
float c = 5F;
StringBuffer sb = new StringBuffer();
說明: 增加 sb 這個變數,如果需要對齊,則給 a、 b、 c 都要增加幾個空格,在變數比較多的
情況下,是非常累贅的事情。
11.【推薦】 不同邏輯、不同語義、不同業務的程式碼之間插入一個空行分隔開來以提升可讀性。
說明: 沒有必要插入多個空行進行隔開。
(四)OOP 規約
1. 【強制】避免通過一個類的物件引用訪問此類的靜態變數或靜態方法,無謂增加編譯器解析成
本,直接用類名來訪問即可。
2. 【強制】所有的覆寫方法,必須加@Override 註解。
說明: getObject()與 get0bject()的問題。一個是字母的 O,一個是數字的 0,加@Override
可以準確判斷是否覆蓋成功。另外,如果在抽象類中對方法簽名進行修改,其實現類會馬上編
譯報錯。
3. 【強制】相同引數型別,相同業務含義,才可以使用 Java 的可變引數,避免使用 Object。
說明: 可變引數必須放置在引數列表的最後。 (提倡同學們儘量不用可變引數程式設計)
正例: public User getUsers(String type, Integer... ids) {...}
4. 【強制】外部正在呼叫或者二方庫依賴的介面,不允許修改方法簽名, 避免對介面呼叫方產生
影響。介面過時必須加@Deprecated 註解,並清晰地說明採用的新介面或者新服務是什麼。
5. 【強制】不能使用過時的類或方法。
說明: java.net.URLDecoder 中的方法 decode(String encodeStr) 這個方法已經過時,應
該使用雙引數 decode(String source, String encode)。介面提供方既然明確是過時介面,
那麼有義務同時提供新的介面; 作為呼叫方來說,有義務去考證過時方法的新實現是什麼。
6. 【強制】 Object 的 equals 方法容易拋空指標異常,應使用常量或確定有值的物件來呼叫
equals。
正例: "test"