本規範的目的是使本組織能以標準的、規範的方式設計和編碼。經過創建編碼規範,使每一個開發人員養成良好的編碼風格和習慣;並以此造成開發小組編碼約定,提升程序的可靠性、可讀性、可修改性、可維護性和一致性等,增進團隊間的交流,並保證軟件產品的質量。java
本規範適用於XXXX有限公司技術部全部軟件開發人員,在整個軟件開發過程當中必須遵循此規範。程序員
² 本文檔爲共享文檔,不限轉載,但請保持本文檔的完整性算法
² 您能夠修改本文檔以符合您或組織、公司等之實際,但請在文檔中保持對本文檔的引用和說明。shell
² 未經產品開發中心受權,任何我的、組織或單位不得將本文檔用於書面發表、轉載、摘錄等,亦不得用於其餘商業行爲。數據庫
² 本人及本組織不承擔任何因使用、參考本文檔等而致使的任何可能責任或連帶責任。express
² 《Java 編程指南》見RUP(Rational Unified Process)中文版。編程
² 《Java技術手冊》(Java in a Nutshell)設計模式
² 《Sun Java語言編碼規範》(Java Code Conventions)數組
² 《Effictive Java》安全
² 《Java Pitfalls》
² 《Java Rules》
對於代碼,首要要求是它必須正確,可以按照設計預約功能去運行;第二是要求代碼必須清晰易懂,使本身和其餘的程序員可以很容易地理解代碼所執行的功能等。然而,在實際開發中,每一個程序員所寫的代碼卻常常自成一套,不多統一,致使理解困難,影響團隊的開發效率及系統的質量等。所以,一份完整並被嚴格執行的開發規範是很是必須的,特別是對軟件公司的開發團隊而言。此規範參考自業界標準編程規範而制定。
最根本的原則:
² 代碼雖然是給機器運行的,但倒是給人讀的!
² 運用常識。當找不到任何規則或指導方針,當規則明顯不能適用,當全部的方法都失效的時侯:運用常識並覈實這些基本原則。這條規則比其它全部規則都重要。常識是必不可少。
² 當出現該狀況時,應當及時收集並提交,以便對本規範進行修改。
代碼的組織和風格的基本原則是:便於本身的開發,易於與他人的交流。
因我的習慣和編輯器等能夠設置和造成本身的風格,但必須先後一致,並符合本規範的基本要求和原則。
本章所涉及到的內容通常均可在Java集成編輯環境中進行相應設置,也可由Ant等調用checkstyle等來進行自動規整。
子功能塊當在其父功能塊後縮進。
當功能塊過多而致使縮進過深時當將子功能塊提取出來作爲子函數。
代碼中以TAB(4個字符)縮進,在編輯器中請將TAB設置爲以空格替代,不然在不一樣編輯器或設置下會致使TAB長度不等而影響整個程序代碼的格式。例如:
Table1.縮進示例
public void methodName(){ if(some condition){ for(…){ //some sentences }//end for }//end if } |
爲便於閱讀和理解,單個函數的有效代碼長度當儘可能控制在100行之內(不包括註釋行),當一個功能模塊過大時每每形成閱讀困難,所以當使用子函數等將相應功能抽取出來,這也有利於提升代碼的重用度。
單個類也不宜過大,當出現此類狀況時當將相應功能的代碼重構到其餘類中,經過組合等方式來調用,建議單個類的長度包括註釋行不超過1500行。
儘可能避免使用大類和長方法。
頁寬應該設置爲150字符。通常不要超過這個寬度, 這會致使在某些機器中沒法以一屏來完整顯示, 但這一設置也能夠靈活調整。在任何狀況下, 超長的語句應該在一個逗號後或一個操做符前折行。一條語句折行後, 應該比原來的語句再縮進一個TAB或4個空格,以便於閱讀。
類、方法及功能塊間等應以空行相隔,以增長可讀性,但不得有無規則的大片空行。操做符兩端應當各空一個字符以增長可讀性。
相應獨立的功能模塊之間可以使用註釋行間隔,並標明相應內容,具體參看附錄的代碼示例。
關係密切的行應對齊,對齊包括類型、修飾、名稱、參數等各部分對齊。
連續賦值時當對齊操做符。
當方法參數過多時當在每一個參數後(逗號後)換行並對齊。
當控制或循環中的條件比較長時當換行(操做符前)、對齊並註釋各條件。
變量定義最好經過添加空格造成對齊,同一類型的變量應放在一塊兒。以下例所示:
Table2.對齊示例
//變量對齊----------------------------------------------- int count = 100; int length = 0; String strUserName = null; Integer[] porductCode = new Integer(2); //產品編碼數組 //參數對齊---------------------------------------------- public Connection getConnection(String url, String userName, String password) throws SQLException,IOException{ } //換行對齊---------------------------------------------- public final static String SQL_SELECT_PRODUCT = 「SELECT * 「 + 「 FROM TProduct WHERE Prod_ID = 」 + prodID; //條件對齊---------------------------------------------- if( Condition1 //當條件一 && Condition2 //而且條件二 || Condition3){ //或者條件三 } for(int i = 0; i < productCount.length; //循環終止條件 i++){ } |
7.
² 註釋應該增長代碼的清晰度。代碼註釋的目的是要使代碼更易於被其餘開發人員等理解。
² 若是你的程序不值得註釋,那麼它極可能也不值得運行。
² 避免使用裝飾性內容。
² 保持註釋的簡潔。
² 註釋信息不只要包括代碼的功能,還應給出緣由。
² 不要爲註釋而註釋。
² 除變量定義等較短語句的註釋可用行尾註釋外,其餘註釋當避免使用行尾註釋。
對類、方法、變量等的註釋須要符合JavaDoc規範,對每一個類、方法都應詳細說明其功能、條件、參數等,並使用良好的HTML標記格式化註釋,以使生成的JavaDoc易閱讀和理解。
在每一個文件的頭部都應該包含該文件的功能、做用、做者、版權以及建立、修改記錄等。並在其中使用SVN標記自動跟蹤版本變化及修改記錄等信息。注意是/**/註釋而不是/***/JavaDoc註釋。
Table3 文件(File)註釋模板
/* * Copyright (C) 2006-${year} 普信恆業科技發展(北京)有限公司. * 本系統是商用軟件,未經受權擅自複製或傳播本程序的部分或所有將是非法的. ============================================================ * FileName: ${file_name} * Created: [${date} ${time}] by ${user} * $$Id$$ * $$Revision$$ * $$Author$$ * $$Date$$ ============================================================ * ProjectName: ${project_name} * Description: ==========================================================*/ |
在類、接口定義以前當對其進行註釋,包括類、接口的目的、做用、功能、繼承於何種父類,實現的接口、實現的算法、使用方法、示例程序等,在做者和版本域中使用SVN標記自動跟蹤版本變化等,具體參看註釋模板。
Table4 類(Types)註釋模板
/** * Description: * @author ${user} * @version 1.0 * <pre> * Modification History: * Date Author Version Description ------------------------------------------------------------------ * ${date} ${user} 1.0 1.0 Version * </pre> */ |
依據標準JavaDoc規範對方法進行註釋,以明確該方法功能、做用、各參數含義以及返回值等。複雜的算法用/**/在方法內註解出。
參數註釋時當註明其取值範圍等
返回值當註釋出失敗、錯誤、異常時的返回狀況。
異常當註釋出什麼狀況、何時、什麼條件下會引起什麼樣的異常。
Table5 方法(Methods)註釋模板
/** * Description: * @param * @return ${return_type} * @throws * @Author ${user} * Create Date: ${date} ${time} */ |
應對重要的變量加以註釋,以說明其含義等。
應對不易理解的分支條件表達式加註釋。不易理解的循環,應說明出口條件。過長的方法實現,應將其語句按實現的功能分段加以歸納性說明。
對於異常處理當註明正常狀況及異常狀況或者條件,並說明當異常發生時程序當如何處理。
Table6 註釋參考表
項目 |
註釋內容 |
參數 |
參數類型 參數用來作什麼 約束或前提條件 示例 |
字段/屬性 |
字段描述 註釋全部使用的不變量 示例 並行事件 可見性決策 |
類 |
類的目的 已知的問題 類的開發/維護歷史、版本 註釋出採用的不變量 並行策略 |
編譯單元 (文件) |
每個類/類內定義的接口,含簡單的說明 文件名和/或標識信息 修改/維護記錄 版權信息 |
獲取成員函數 |
若可能,說明爲何使用滯後初始化 |
接口 |
目的 它應如何被使用以及如何不被使用 |
局部變量 |
用處/目的 |
成員函數註釋 |
成員函數作什麼以及它爲何作這個 哪些參數必須傳遞給一個成員函數 成員函數返回什麼 已知的問題 任何由某個成員函數拋出的異常 可見性決策 成員函數是如何改變對象的 包含任何修改代碼的歷史 如何在適當狀況下調用成員函數的例子 適用的前提條件和後置條件 |
成員函數內部註釋 |
控制結構 代碼作了些什麼以及爲何這樣作 局部變量 |
難或複雜的代碼處理順序 |
|
包 |
包的功能和用途 |
8.
規範的命名能使程序更易閱讀,從而更易於理解。它們也能夠提供一些標識功能方面的信息,有助於更好的理解代碼和應用。
1) 使用能夠準確說明變量/字段/類/接口/包等的完整的英文描述符。例如,採用相似 firstName,listAllUsers 或 CorporateCustomer 這樣的名字,嚴禁使用漢語拼音及不相關單詞命名,雖然Java支持Unicode命名,但本規範規定對包、類、接口、方法、變量、字段等不得使用漢字等進行命名。
2) 採用該領域的術語。若是用戶稱他們的「客戶」 (clients) 爲「顧客」 (customers),那麼就採用術語 Customer 來命名這個類,而不用 Client。
3) 採用大小寫混合,提升名字的可讀性。通常應該採用小寫字母,可是類和接口的名字的首字母,以及任何中間單詞的首字母應該大寫。包名所有小寫。
4) 儘可能少用縮寫,但若是必定要使用,當使用公共縮寫和習慣縮寫等,如實現(implement)可縮寫成impl,經理(manager)可縮寫成mgr等,具體參看附錄之《經常使用縮寫簡表》,嚴禁濫用縮寫。
5) 避免使用長名字(最好不超過 25 個字母)。
6) 避免使用類似或者僅在大小寫上有區別的名字。
7) 避免使用數字,但可用2代替to,用4代替for等,如:go2Jsp。
1) 文件名當與其類嚴格相同,全部單詞首字母大寫。
2) 包名通常以項目或模塊名命名,少用縮寫和長名,一概小寫。
3) 基本包:org.skyinn,全部包、文件都從屬於此包。
4) 包名按以下規則組成:
[基本包].[項目名].[模塊名].[子模塊名]...
如:
org.skyinn.quasar
org.skyinn.skyhome.dao.hibernate
5) 不得將類直接定義在基本包下,全部項目中的類、接口等都當定義在各自的項目和模塊包中。
6) 自主開發程序的命名規則爲:com.creditease.XXXX
全部單詞首字母大寫。使用能確切反應該類、接口含義、功能等的詞。通常採用名詞。
接口文件名前添加大寫字母「I」,其後使用able。
採用完整的英文大寫單詞,在詞與詞之間用下劃線鏈接,如:DEFAULT_VALUE。
對不易清楚識別出該變量類型的變量應使用類型縮寫做其前綴,如字符串使用strXXX,boolean使用isXXX,hasXXX等等。除第一各個單詞外其他單詞首字母大寫。
對私有實例變量可以使用_前綴,但在其存取方法中則應該將其前綴去掉。
應採用完整的英文描述符命名組件(接口部件),遵循匈牙利命名法則。
如:btnOK,lblName。
一個集合,例如數組和矢量,應採用複數命名來表示隊列中存放的對象類型。命名應採用完整的英文描述符,名字中全部非開頭的單詞的第一個字母應大寫,適當使用集合縮寫前綴。如:
Vector vProducts = new Vector(); //產品向量
Array aryUsers = new Array(); //用戶列表
咱們在程序裏常常會用到一些量,它是有特定的含義的。例如,如今咱們寫一個薪金統計程序,公司員工有50人,咱們在程序裏就會用50這個數去進行各類各樣的運算。在這裏,50就是"神祕的數"。當別的程序員在程序裏看到50這個數,將很難知道它的含義,形成理解上的困難。
在程序裏出現"神祕的數"會下降程序的可讀性、可維護性和可擴展性,故規定不得出現此類"神祕的數"。避免的方法是把神祕的數定義爲一個常量。注意這個常量的命名應該能表達該數的意義,而且應該所有大寫,以與對應於變量的標識符區別開來。例如上面50這個數,咱們能夠定義爲一個名爲NUM_OF_EMPLOYEES的常量來代替。這樣,別的程序員在讀程序的時候就能夠容易理解了。
命名時應使用複數來表示它們表明多值。如:orderItems。
方法的命名應採用完整的英文描述符,大小寫混合使用:全部中間單詞的第一個字母大寫。方法名稱的第一個單詞經常採用一個有強烈動做色彩的動詞。
取值類使用get前綴,設值類使用set前綴,判斷類使用is(has)前綴。
例: getName()
setSarry()
isLogon()
方法參數建議順序:(被操做者,操做內容,操做標誌,其餘⋯)
例:public void replace(String sourceStr, //源字串
String oldStr, //被替換字串
String newStr){ //替換爲字串
異常類名由表示該異常類型的單詞和Exception組成,如ActionException。
異常實例通常使用e、ex等,在多個異常時使用該異常名或簡寫加E,Ex等組成,如:
SQLEx
ActionEx
Table7 命名約定表
操做項 |
命名約定 |
示例 |
|
參數 |
使用傳遞值/對象的完整的英文描述符。 |
userID |
|
字段/屬性 |
字段採用完整的英文描述,第一個字母小寫,任何中間單詞的首字母大寫。 |
firstName |
|
布爾型的獲取成員函數 |
全部的布爾型獲取函數必須用單詞 is(has)作前綴。 |
isString() hasMoney() |
|
類 |
採用完整的英文描述符,全部單詞的第一個字母大寫。 |
Customer |
|
編譯單元文件 |
使用類或接口的名字,或者若是文件中除了主類以外還有多個類時,加上前綴 java 來講明它是一個源碼文件。 |
Customer.java |
|
部件/組件 |
使用完整的英文描述來講明組件的用途,將組件類型使用匈牙利命名法則做其前綴。 |
btnOK,cboTypeList |
|
構造函數 |
使用類名 |
Customer() |
|
析構函數 |
Java 沒有析構函數,但一個對象在垃圾收集時,調用成員函數 finalize() 。 |
finalize() |
|
異常類名 |
由表示該異常類型等的單詞和Exception組成 |
SQLException ActionException |
|
異常實例名 |
一般採用字母 e 、ex表示異常。 多個異常時使用異常名或其簡寫加E、Ex等構成 |
e SQLEx |
|
靜態常量字段(常量) |
所有采用大寫字母,單詞之間用下劃線分隔。採用靜態常量獲取成員函數。 |
DEFAULT_NAME |
|
獲取成員函數 |
被訪問字段名的前面加上前綴 get。 |
getUserName() |
|
接口 |
採用完整的英文描述符說明接口封裝,全部單詞的第一個字母大寫。使用I前綴,其後使用able,或者 er等後綴,但這不是必需的 |
IRunnable IPrompter |
|
局部變量 |
採用完整的英文描述符,第一個字母小寫,但不要隱藏已有字段。例如,若是有一個字段叫 firstName,不要讓一個局部變量叫 firstName。 |
strName,totalMoney |
|
循環計數器 |
一般採用字母 i,j,k 或者 counter,index |
i,j,k,count,index |
|
包 |
採用完整的英文描述符,全部單詞都小寫,多個單詞如下劃線相連。全部包都屬於 org.skyinn |
org.skyinn.quasar org.skyinn.skyhome.dao |
|
成員函數 |
採用完整的英文描述說明成員函數功能,第一個單詞儘量採用一個生動的動詞,除第一個單詞外,每一個單詞第一個字母小寫。 |
openFile() addUser() |
|
設置成員函數 |
被訪問字段名的前面加上前綴 set。 |
setName() setPower() |
9.
聲明的基本原則是遵照Java語言規範,並聽從習慣用法。
在導入包時當徹底限制代碼所使用的類的名字,儘可能少用通配符的方式,但導入一些通用包,或用到一個包下大部分類時,則但是使用通配符方式,如:
import org.skyinn.quasar.services.Service;
import java.util.*;
同一包中的類導入時當聲明在一塊兒,可由編輯器自動完成此功能。
重要的包當添加註釋。
類、接口定義語法規範:
[可見性][('abstract'|'final')] [Class|Interface] class_name
[('extends'|'implements')][父類或接口名]{
}
如:
public class LoginAction extends BaseAction implemnets ActionListener {
}
良好的程序設計應該儘量減少類與類之間耦合,所遵循的經驗法則是:儘可能限制成員函數的可見性。若是成員函數不必公有 (public),就定義爲保護 (protected);不必保護 (protected),就定義爲私有 (private)。
方法定義語法規範:
[可見性][('abstract'|'final')] ['synchronized'][返回值類型] method_name(參數列表)[('throws')][異常列表]{
// 功能模塊
}
如:
public List listAllUsers() throws DAOException{}
如有toString(),equals(),hashCode(),colone()等重載自Object的方法,應將其放在類的最後。
聲明順序:
構造方法
靜態公共方法
靜態私有方法
受保護方法
私有方法
繼承自Object的方法
字段定義語法規範:
[(‘public’|’private’|’protected’)]
[(‘final’|’volatile’)][‘static’][‘transient’]
data_type field_name [ ‘=’ expression] ‘;’
若沒有足夠理由,不要把實例或類變量聲明爲公有。公共和保護的可見性應當儘可能避免,全部的字段都建議置爲私有,由獲取和設置成員函數(Getter、Setter)訪問。
不容許「隱藏」字段,即給局部變量所取的名字,不可與另外一個更大範圍內定義的字段的名字相同(或類似)。例如,若是把一個字段叫作 firstName ,就不要再生成一個局部變量叫作 firstName,或者任何易混餚的名字,如 fistName。
數組聲明時當將"[]"跟再類型後,而不時字段名後,如:
Integer[] ai = new Integer (2); //一個整數對象數組,用於...
Integer aj[] = new Integer (3); //不要用這種數組聲明方式
一行代碼只聲明一個變量,僅將一個變量用於一件事。
聲明順序:
常量
類變量
實例變量
公有字段
受保護字段
私有字段
能夠將私有變量聲明在類或接口的最後。
注意受保護變量、私有變量、「包」變量間的區別。
Table8
//常量--------------------------------------------------- public final static double PI = 3.141592653589793; // -------------------------------------------------類變量 protected static String key = 「Love」; // -----------------------------------------------實例變量 //共有字段----------------------------------------------- public String userName = 「Tom」; //受保護字段--------------------------------------------- protected float price = 0.0; //友元字段----------------------------------------------- Vector vPorducts = null; //私有字段----------------------------------------------- private int count; |
|
//構造方法----------------------------------------------- public Constructor(){ } //公共方法----------------------------------------------- public String getUserName(){ } //友元方法----------------------------------------------- void createProduct(){ } //受保護方法--------------------------------------------- protected void convert(){ } //私有方法----------------------------------------------- private void init(){ } //重載Object方法---------------------------------------- public String toString(){ } //main方法----------------------------------------------- public static void main(String[] args){ } |
|
10.
類的劃分粒度,不可太大,形成過於龐大的單個類,也不可太細,從而使類的繼承太深。通常而言,一個類只作一件事;另外一個原則是根據每一個類的職責進行劃分,好比用User來存放用戶信息,而用UserDAO來對用戶信息進行數據訪問操做(好比存取數據庫),用UserBroker來封裝用戶信息的業務操做等等。
多使用設計模式,隨時重構。
多個類中使用相同方法時將其方法提到一個接口中或使用抽象類,儘可能提升重用度。
將不但願再被繼承的類聲明成final,例如某些實用類,但不要濫用final,不然會對系統的可擴展性形成影響。
將不但願被實例化的類的缺省構造方法聲明成private。
通常而言:接口定義行爲,而抽象類定義屬性和公有行爲,注意二者間的取捨,在設計中,可由接口定義公用的行爲,由一個抽象類來實現其部分或所有方法,以給子類提供統一的行爲定義,可參考Java集合等實現。
多使用接口,儘可能作到面向接口的設計,以提升系統的可擴展性。
儘可能使用組合來代替繼承,一則可使類的層次不至於過深,並且會使類與類,包與包之間的耦合度更小,更具可擴展性。
當須要使用多個構造函數建立類時,建議使用靜態工廠方法替代這些構造方法(參考《Effictive Java》 Item1),例如:
public class User{
public User(){
super();
//do somethings to create user instance
}
public static User getInstance(String name,String password){
User u = new User();
u.setName(name);
u.setPassword(password);
return u;
}
參看String,Boolean的實現等:String.valueOf(Long l),Boolean.valueOf(String)...
每一個類都應該重載toString()方法,以使該類能輸出必要和有用的信息等。
/** * @see java.lang.Object#toString() */ public String toString() { final StringBuffer sb = new StringBuffer("Actor:["); sb.append("ID = ").append(_id) .append(",Name = ").append(_name) .append(']'); return sb.toString(); } |
若一個類須要重載equals()方法,則必須同時重載hashCode()方法實現方式參考《Effictive Java》Item7,Item8
/** * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals (Object obj) { //空值 if( null == obj){ return false; } //引用相等 if (obj == this) { return true; } //判斷是否爲當前類實例 if (!(obj instanceof Actor)) { return false; } //若ID相等則認爲該對象相等 return this._id == ((Actor) obj).getId (); } /** * @see java.lang.Object#hashCode() */ public int hashCode () { int result = 17;//init result //String 對象hashCode result = (37 * result) + _name.hashCode (); //數值 result = (37 * result) + (int) (_id ^ (_id >>> 32)); //String 對象hashCode result = (37 * result) + _description.hashCode (); return result; } |
這些方法的重載實現也可參考以下實現(使用Jakarta commons-lang):
單例類使用以下方式聲明,並將其缺省構造方法聲明成private:
public class Singleton{
private static Singleton instance = new Singleton();
// 私有缺省構造方法,避免被其餘類實例化
private Singleton(){
//do something
}
public static Singleton getInstance(){
if(null == instance){
instance = new Singleton;
}
return instance;
}
}//EOC Singleton
單例類若須要實現序列化,則必須提供readResolve()方法,以使反序列化出來的類仍然是惟一的實例,參見《Effictive Java》 Item57。
11.
一個方法只完成一項功能,在定義系統的公用接口方法外的方法應儘量的縮小其可見性。
避免用一個類是實例去訪問其靜態變量和方法。
避免在一個較長的方法裏提供多個出口:
//不要使用這鐘方式,當處理程序段很長時將很難找到出口點 if(condition){ return A; }else{ return B; } //建議使用以下方式 String result = null; if(condition){ result = A; }else{ result = B; } return result; |
避免過多的參數列表,儘可能控制在5個之內,若須要傳遞多個參數時,當使用一個容納這些參數的對象進行傳遞,以提升程序的可讀性和可擴展性。
參數類型和返回值儘可能接口化,以屏蔽具體的實現細節,提升系統的可擴展性,例如:
public void joinGroup(List userList){}
public List listAllUsers(){}
12.
表達式和語句當清晰、簡潔,易於閱讀和理解,避免使用晦澀難懂的語句。
每行至多包含一條執行語句,過長當換行。
避免在構造方法中執行大量耗時的初始化工做,應當將這中工做延遲到被使用時再建立相應資源,若是不可避免,則當使用對象池和Cache等技術提升系統性能。
避免在一個語句中給多個變量賦相同的值。它很難讀懂。
不要使用內嵌(embedded)賦值運算符試圖提升運行時的效率,這是編譯器的工做。
儘可能在聲明局部變量的同時初始化。惟一不這麼作的理由是變量的初始值依賴於某些先前發生的計算。
通常而言,在含有多種運算符的表達式中使用圓括號來避免運算符優先級問題,是個好方法。即便運算符的優先級對你而言可能很清楚,但對其餘人未必如此。你不能假設別的程序員和你同樣清楚運算符的優先級。
不要爲了表現編程技巧而過度使用技巧,簡單就好。
判斷中若有常量,則應將常量置與判斷式的左側。如:
if ( true == isAdmin())...
if ( null == user)...
儘可能不使用三目條件判斷。
全部if語句必須用{}包括起來,即使是隻有一句:
if (true){ //do something...... } if (true) i = 0; //不要使用這種 |
當有多個else分句時當分別註明其條件,注意縮進並對齊,如:
//先判斷i 是否等於1 if (i == 1){//if_1 //..... }//而後判斷i == 2 else if (i == 2){ //i == 2說明。。。。。。 j = i; }//若是都不是(i > 2 || i < 1) else{ //說明出錯了 //.... }//end if_1 |
過多的else分句請將其轉成switch語句或使用子函數。
每當一個case順着往下執行時(由於沒有break語句),一般應在break語句的位置添加註釋。如:
switch (condition) { case ABC: //statements; //繼續下一個CASE case DEF: //statements; break; case XYZ: //statements; break; default: //statements; break; }//end switch |
循環中必須有終止循環的條件或語句,避免死循環。
當在for語句的初始化或更新子句中使用逗號時,避免因使用三個以上變量,而致使複雜度提升。若須要,能夠在for循環以前(爲初始化子句)或for循環末尾(爲更新子句)使用單獨的語句。
由於循環條件在每次循環中多會執行一次,故儘可能避免在其中調用耗時或費資源的操做,比較一下兩種循環的差別:
//不推薦方式____________________________________________ while(index < products.getCount()){ //每此都會執行一次getCount()方法, //若此方法耗時則會影響執行效率 //並且可能帶來同步問題,如有同步需求,請使用同步塊或同步方法 } //推薦方式______________________________________________ //將操做結構保存在臨時變量裏,減小方法調用次數 final int count = products.getCount(); while(index < count){ } |
13.
一般的思想是隻對錯誤採用異常處理:邏輯和編程錯誤,設置錯誤,被破壞的數據,資源耗盡,等等。
一般的法則是系統在正常狀態下以及無重載和硬件失效狀態下,不該產生任何異常。
最小化從一個給定的抽象類中導出的異常的個數。
對於常常發生的可預計事件不要採用異常。
不要使用異常實現控制結構。
確保狀態碼有一個正確值。
在本地進行安全性檢查,而不是讓用戶去作。
如有finally子句,則不要在try塊中直接返回,亦不要在finally中直接返回。
已檢查異常必須捕捉並作相應處理,不能將已檢查異常拋到系統以外去處理。
對可預見的運行時異常當進行捕捉並處理,好比空指針等。一般,對空指針的判斷不是使用捕捉NullPointException的方式,而是在調用該對象以前使用判斷語句進行直接判斷,如:
//若不對list是否爲null進行檢查,則在其爲null時會拋出空指針異常
if(null != list && 0 < list.size()){
for(int i = 0; i < list.size(); i++){
}
}
建議使用運行時異常(RuntimeException)代替已檢查異常(CheckedException),請參考網絡資源以對此兩種異常作更深刻理解。
捕捉異常是爲了處理它,不要捕捉了卻什麼都不處理而拋棄之,最低限度當向控制檯輸出當前異常,若是你不想處理它,請將該異常拋給它的調用者,建議對每一個捕捉到的異常都調用printStackTrace()輸出異常信息,避免因異常的湮沒。
多個異常應分別捕捉並處理,避免使用一個單一的catch來處理。如:
try { //do something }catch(IllegalStateException IllEx){ IllEx.printStackTrace(); //deal with IllEx }catch(SQLException SQLEx){ SQLEx.printStackTrace(); throw SQLEx; //拋給調用者處理 }finally{ //釋放資源 } |
14.
測試不經過的代碼不得提交到SVN庫或者發佈。
不得隱瞞、忽略、繞過任何Bug,有Bug不必定是你的錯,但有了Bug不做爲就是你的不對了。
多作測試,測試要徹底,儘可能將各類可能狀況都測試經過,儘可能將可能的Bug在開發中捕捉並處理掉。
測試要保證可再測試性。
測試應當對數據庫等資源不留或少留痕跡,例如,當測試添加一個用戶時,在其成功後當及時從數據庫中刪除該記錄,以免髒數據的產生(由此衍生的一個經驗是將添加、獲取、刪除一塊兒測試)。
對關鍵功能必須測試並經過,對輔助功能及很是簡單之功能可不作測試。
在Java應用中,單元測試使用Junit及其衍生工具。
在TestCase的setUp()中初始化應用,在tearDown()中釋放資源。可由一個基礎TestCase完成這些任務,其餘TestCase繼承之。
由持續集成工具來完成代碼編譯與自動部署,參見《持續集成規程》。
當系統出現Bug時當由該Bug的負責人(代碼負責人)儘快修改之。
Bug的處理根據其優先級高低和級別高低前後處理。
Bug級別和優先級別參見《軟件測試規程》。
禁止隱瞞Bug。
15.
性能的提高並非一蹴而就的,而是由良好的編程積累的,雖然任何良好的習慣和經驗所提高的性能都十分有限,甚至微乎其微,但良好的系統性能倒是由這些習慣等積累而成,不積細流,無以成江海!
不要使用以下String初始化方法:
String str = new String(「abcdef」);
這將產生兩個對象,應當直接賦值:
String str = 「abcdef」;
在處理可變 String 的時候要儘可能使用 StringBuffer 類,StringBuffer 類是構成 String 類的基礎。String 類將 StringBuffer 類封裝了起來,(以花費更多時間爲代價)爲開發人員提供了一個安全的接口。當咱們在構造字符串的時候,咱們應該用 StringBuffer 來實現大部分的工做,當工做完成後將 StringBuffer 對象再轉換爲須要的 String 對象。好比:若是有一個字符串必須不斷地在其後添加許多字符來完成構造,那麼咱們應該使用 StringBuffer 對象及其 append() 方法。若是咱們用 String 對象代替 StringBuffer 對象的話,將會花費許多沒必要要的建立和釋放對象的 CPU 時間。
避免使用Vector和HashTable等舊的集合實現,這些實現的存在僅是爲了與舊的系統兼容,並且因爲這些實現是同步的,故而在大量操做時會帶來沒必要要的性能損失。在新的系統設計中不當出現這些實現,使用ArrayList代替Vector,使用HashMap代替HashTable。
若倒是須要使用同步集合類,當使用以下方式得到同步集合實例:
Map map = Collections.synchronizedMap(new HashMap());
因爲數組、ArrayList與Vector之間的性能差別巨大(具體參見《Java fitball》),故在能使用數組時不要使用ArrayList,儘可能避免使用Vector。
避免在循環中頻繁構建和釋放對象。
再也不使用的對象應及時銷燬。
如無必要,不要序列化對象。
在不須要同步操做時避免使用同步操做類,如能使用ArrayList時不要使用Vector。
儘可能少用同步方法,避免使用太多的 synchronized 關鍵字。
儘可能將同步最小化,即將同步做用到最須要的地方,避免大塊的同步塊或方法等。
將參數或方法聲明成final可提升程序響應效率,故此:
注意絕對不要僅由於性能而將類、方法等聲明成final,聲明成final的類、方法必定要確信再也不被繼承或重載!
不須要從新賦值的變量(包括類變量、實例變量、局部變量)聲明成final
全部方法參數聲明成final
私有(private)方法不須要聲明成final,若方法肯定不會被繼承,則聲明成final。
不要過度依賴JVM的垃圾收集機制,由於你沒法預測和知道JVM在何時運行GC。
儘量早的釋放資源,再也不使用的資源請當即釋放。
可能有異常的操做時必須在try的finally塊中釋放資源,如數據庫鏈接、IO操做等:
Connection conn = null; try{ //do something }catch(Exception e){ //異常捕捉和處理 e.printStackTrack(); }finally{ //判斷conn等是否爲null if(null != conn){ conn.close(); } }//end try...catch...finally |
16.
主鍵類型:
字符串/整型值。推薦使用字符型作主鍵,如有性能要求,容許使用數值類型
生成機制:
字符串:生成UUID,或者GUID
整型值:使用數據庫序列
生成方法:
根據公司數據庫系統的實際狀況,並遵循複雜度最小化原則,分別就hibernate及iBatis兩個持久層框架的主鍵生成策略進行限定:
1. hibernate
要求使用如下主鍵生成策略的任意一種:
(1)sequence(序列):用於爲整數類型的主鍵生成
數據庫中的語法以下:
Oracle:create sequence seq_name increment by 1 start with 1;
須要主鍵值時能夠調用seq_name.nextval或者seq_name.curval獲得,數據庫會幫助咱們維護這個sequence序列,保證每次取到的值惟一,示例以下:
insert into tbl_name(id, name) values(seq_name.nextval, ‘Jimliu’);
<id name="id" column="id" type="long">
<generator class="sequence">
<param name="sequence">seq_name</param>
</generator>
</id>
若是咱們沒有指定sequence參數,則Hibernate會訪問一個默認的sequence,是hibernate_sequence,咱們也須要在數據庫中創建這個sequence。
此外,sequence還能夠有另一個參數是paramters,能夠查看Hibernate的API瞭解它的用法,見org.hibernate.id.SequenceGenerator。
調用數據庫的sequence來生成主鍵,要設定序列名,否則hibernate沒法找到:
<param name="sequence">NAME_SEQ</param>
(2)uuid.hex:用於爲字符串類型的主鍵生成
使用一個128-bit的UUID算法生成字符串類型的標識符,UUID被編碼成一個32位16進制數字的字符串。UUID包含:IP地址、JVM啓動時間、系統時間(精確到1/4秒)和一個計數器值(JVM中惟一) hibernate會算出一個128位的惟一值插入。
配置示例以下:
<id name="id" column="id">
<generator class="uuid.hex" />
</id>
2. iBatis
要求使用如下主鍵生成策略:
(1)sequence(序列):用於爲整數類型的主鍵生成
因爲公司項目數據庫多數使用oracle,可以使ibatis中對oracle數據表的主鍵自增加的使用方法。
假設有用戶表User,該表主鍵爲userid,當咱們但願該字段可以自動增加而不須要人工插值的狀況下,具體步驟以下:
先創建序列 Create sequence seq_user_userid minvalue 1 maxvalue 999999999 increment by 1 start with 1;
在須要對該表插入新記錄的時候,可以使用序列seq_user_userid的nextval來代替主鍵字段的插入,如咱們能夠在相應的xml配置文件中寫:
<insert id=」insert_user」 parameterClass=」user」>
<selectKey resultClass=」int 」 type=」pre」 keyProperty=」userid」>
Select seq_user_userid.nextval as value from dual //獲取序列的最新值,並賦給userid
</selectKey>
Insert into user(userid,name,age) values (#userid#,#name#,#age#) //將userid表明的序列值插入新記錄的主鍵字段
</insert>
在你的業務邏輯Dao中,具體方法調用insert_user項執行數據庫操做便可。
(2)UUID:用於爲字符串類型的主鍵生成
java.util.UUID.randomUUID().toString().replaceAll("-", "").toUpperCase()
生成結果:C8F6E30AE0994A16A87C4BFB7FC92F58
3. ORACLE中,要求使用如下主鍵生成策略
(1) 數值型主鍵生成方法:
略,同序列的使用。
(2) 字符型主鍵生成方法:
select sys_guid() from dual ,結果示例:47962A3B0FD34B5F800D4D0CEC8D7368