1 Java 編程規範
1.1 排版
1.1.1 規則
規則1 程序塊要採用縮進風格編寫,縮進的空格數爲4個,不允許使用TAB縮進。
說明:縮進使程序更易閱讀,使用空格縮進可以適應不同操作系統與不同開發工具。
規則2 分界符(如大括號‘{’和‘}’)應各獨佔一行,同時與引用它們的語句左對齊。在函數體的開始、類和接口的定義、以及if、for、do、while、switch、case語句中的程序或者static、,synchronized等語句塊中都要採用如上的縮進方式。
示例:
if (a>b)
{
doStart();
}
規則3 較長的語句、表達式或參數(>80字符)要分成多行書寫,長表達式要在低優先級操作符處劃分新行,操作符放在新行之首,劃分出的新行要進行適當的縮進,使排版整齊,語句可讀。
示例:
if(logger.isDebugEnabled())
{
logger.debug("Session destroyed,call-id"
+event.getSession().getCallId());
}
規則4 不允許把多個短語句寫在一行中,即一行只寫一條語句
說明:閱讀代碼更加清晰
示例:如下例子不符合規範。
Objecto = new Object(); Object b = null;
規則5 if, for, do, while, case, switch, default 等語句自佔一行,且if, for, do, while,switch等語句的執行語句無論多少都要加括號{},case 的執行語句中如果定義變量必須加括號{}。
說明:閱讀代碼更加清晰,減少錯誤產生
示例:
if (a>b)
{
doStart();
}
case x:
{
inti = 9;
}
規則6 相對獨立的程序塊之間、變量說明之後必須加空行。
說明:閱讀代碼更加清晰
示例:
if(a > b)
{
doStart();
}
//此處是空行
return;
規則7 在兩個以上的關鍵字、變量、常量進行對等操作時,它們之間的操作符之前、之後或者前後要加空格;進行非對等操作時,如果是關係密切的立即操作符(如.),後不應加空格。
說明:閱讀代碼更加清晰
示例:
if (a == b)
{
objectA.doStart();
}
a *= 2;
1.1.2 建議
建議1 類屬性和類方法不要交叉放置,不同存取範圍的屬性或者方法也儘量不要交叉放置。
格式:
類定義
{
類的公有屬性定義
類的保護屬性定義
類的私有屬性定義
類的公有方法定義
類的保護方法定義
類的私有方法定義
}
建議2 修飾詞按照指定順序書寫:[訪問權限][static][final] 。
示例:
publicstatic final String str = “abc”;
1.2 註釋
1.2.1 規則
規則1 源程序註釋量必須在30%以上。
說明:由於每個文件的代碼註釋不一定都可以達到30%,建議以一個系統內部模塊作爲單位進行檢查
規則2 包的註釋:寫入一個名爲 package.html的HTML格式的說明文件放入包所在路徑。包的註釋內容:簡述本包的作用、詳細描述本包的內容、產品模塊名稱和版本、公司版權。
說明:方便JavaDoc收集,方便對包的瞭解
示例:
com/huawei/iin/websmap/comm/package.html
一句話簡述。
詳細描述。
產品模塊名稱和版本
公司版權信息
示例:
爲WEBSMAP 提供通信類,上層業務使用本包的通信類與SMP-B 進行通信。
詳細描述。。。。。。。。
IINV100R001 WEBSMAP
(C)版權所有 2000-2001 華爲技術有限公司
規則3 類和接口的註釋放在class 或者 interface 關鍵字之前,import 關鍵字之後。註釋主要是一句話功能簡述與功能詳細描述。類註釋使用“/* /”註釋方式
說明:方便JavaDoc收集,沒有import可放在package之後。註釋可根據需要列出:作者、內容、功能、與其它類的關係等。功能詳細描述部分說明該類或者接口的功能、作用、使用方法和注意事項,每次修改後增加作者和更新版本號和日期,@since 表示從那個版本開始就有這個類或者接口,@deprecated 表示不建議使用該類或者接口。
/**
〈一句話功能簡述〉
〈功能詳細描述〉
@author [作者](必須)
- @see [相關類/方法](可選)
@since [產品/模塊版本] (必須)
@deprecated (可選)
*/
示例:
packagecom.huawei.iin.logwebsmap.comm;
importjava.util.*;
/**
LogManager 類集中控制對日誌讀寫的操作。
全部爲靜態變量和靜態方法,對外提供統一接口。分配對應日誌類型的讀寫器,
讀取或寫入符合條件的日誌紀錄。
@author 張三,李四,王五
- @see LogIteraotor
@see BasicLog
@since CommonLog1.0
*/
publicclass LogManager
規則4 類屬性(成員變量)、公有和保護方法註釋:寫在類屬性、公有和保護方法上面,註釋方式爲“/* /”.
示例:
/**
註釋內容
*/
privateString logType;
/**
註釋內容
*/
publicvoid write()
規則5 公有和保護方法註釋內容:列出方法的一句話功能簡述、功能詳細描述、輸入參數、輸出參數、返回值、異常等。
格式:
/**
〈一句話功能簡述〉
〈功能詳細描述〉
@param [參數1] [參數1說明]
@param [參數2] [參數2說明]
@return [返回類型說明]
@exception/throws [異常類型] [異常說明]
@see [類、類#方法、類#成員]
- @since [起始版本]
@deprecated
*/
說明:@since 表示從那個版本開始就有這個方法,如果是最初版本就存在的方法無需說明;@exception或throws 列出可能仍出的異常;@deprecated 表示不建議使用該方法。
示例:
/**
* 根據日誌類型和時間讀取日誌。
* 分配對應日誌類型的LogReader, 指定類型、查詢時間段、條件和反覆器緩衝數,
* 讀取日誌記錄。查詢條件爲null或0的表示沒有限制,反覆器緩衝數爲0讀不到日誌。
* 查詢時間爲左包含原則,即[startTime, endTime) 。
* @param logTypeName 日誌類型名(在配置文件中定義的)
* @param startTime 查詢日誌的開始時間
* @param endTime 查詢日誌的結束時間
* @param logLevel 查詢日誌的級別
*@param userName 查詢該用戶的日誌
* @param bufferNum 日誌反覆器緩衝記錄數
* @return 結果集,日誌反覆器
* @since 1.2
*/
public static LogIterator read(StringlogType, Date startTime, Date endTime, intlogLevel, String userName, int bufferNum)
規則6 對於方法內部用throw語句拋出的異常,必須在方法的註釋中標明,對於所調用的其他方法所拋出的異常,選擇主要的在註釋中說明。 對於非RuntimeException,即throws子句聲明會拋出的異常,必須在方法的註釋中標明。
說明:異常註釋用@exception或@throws表示,在JavaDoc中兩者等價,但推薦用@exception標註Runtime異常,@throws標註非Runtime異常。異常的註釋必須說明該異常的含義及什麼條件下拋出該異常。
規則7 註釋應與其描述的代碼相近,對代碼的註釋應放在其上方,並與其上面的代碼用空行隔開,註釋與所描述內容進行同樣的縮排。
說明:可使程序排版整齊,並方便註釋的閱讀與理解。
示例:
/*
- 註釋
*/
publicvoid example2( )
{
// 註釋
CodeBlock One
// 註釋
CodeBlock Two
}
/*
- 註釋
*/
publicvoid example( )
{
// 註釋
CodeBlock One
// 註釋
CodeBlock Two
}
規則8 對於switch語句下的case語句,必須在每個case分支結束前加上break語句。
說明:break才能真正表示該switch執行結束,不然可能會進入該case以後的分支。至於語法上合法的場景“一個case後進入下一個case處理”,應該在編碼設計上就避免。
規則9 修改代碼同時修改相應的註釋,以保證註釋與代碼的一致性。不再有用的註釋要刪除。
規則10 註釋的內容要清楚、明瞭,含義準確,防止註釋二義性。
說明:錯誤的註釋不但無益反而有害。
規則11 避免在註釋中使用縮寫,特別是不常用縮寫。
說明:在使用縮寫時或之前,應對縮寫進行必要的說明。
規則12 對重載父類的方法必須進行@Override聲明(5.0+)
說明:可清楚說明此方法是重載父類的方法,保證重載父類的方法時不會因爲單詞寫錯而造成錯誤(寫錯方法名或者參數個數,類型都會編譯無法通過)
示例:
@Override
public voiddoRequest(SipServletRequest req) throws ServletException,
IOException
1.2.2 建議
建議1 避免在一行代碼或表達式的中間插入註釋。
說明:除非必要,不應在代碼或表達中間插入註釋,否則容易使代碼可理解性變差。
建議2 在代碼的功能、意圖層次上進行註釋,提供有用、額外的信息。
說明:註釋的目的是解釋代碼的目的、功能和採用的方法,提供代碼以外的信息,幫助讀者理解代碼,防止沒必要的重複註釋信息。
示例:如下注釋意義不大。
// 如果receiveFlag 爲真
if(receiveFlag)
而如下的註釋則給出了額外有用的信息。
//如果從連結收到消息
if(receiveFlag)
建議3 對關鍵變量的定義和分支語句(條件分支、循環語句等)必須編寫註釋。
說明:這些語句往往是程序實現某一特定功能的關鍵,對於維護人員來說,良好的註釋幫助更好的理解程序,有時甚至優於看設計文檔。
建議4 註釋應考慮程序易讀及外觀排版的因素,使用的語言若是中、英兼有的,建議多使用中文,除非能用非常流利準確的英文表達。中文註釋中需使用中文標點。方法和類描述的第一句話儘量使用簡潔明瞭的話概括一下功能,然後加以句號。接下來的部分可以詳細描述。
說明:註釋語言不統一,影響程序易讀性和外觀排版,出於對維護人員的考慮,建議使用中文。JavaDoc工具收集簡介的時候使用選取第一句話。
建議5 方法內的單行註釋使用 //。
說明:調試程序的時候可以方便的使用/* 。。。*/ 註釋掉一長段程序。
建議6 一些複雜的代碼需要說明。
示例:這裏主要是對閏年算法的說明。
//1. 如果能被4整除,是閏年;
//2. 如果能被100整除,不是閏年;
//3. 如果能被400整除,是閏年。
建議7 使用Html標籤使JavaDoc生成更加美觀。
示例:
/**
* Returns a hash code for this string. Thehash code for a
* <code>String</code> objectis computed as
* <blockquote><pre>
* s[0]*31^(n-1) + s[1]*31^(n-2) + ... +s[n-1]
* </pre></blockquote>
* using <code>int</code>arithmetic, where <code>s[i]</code> is the
* <i>i</i>th character of thestring, <code>n</code> is the length * of
* the string, and<code>^</code> indicates exponentiation.
* (The hash value of the empty string iszero.)
*
* @return a hash code value for this object.
*/
public int hashCode()
生成後的JavaDoc
圖1 生成後的JavaDoc
1.3 命名
1.3.1 規則
規則1 類名和接口使用類意義完整的英文描述,每個英文單詞的首字母使用大寫、其餘字母使用小寫的大小寫混合法。
示例:OrderInformation,CustomerList, LogManager, LogConfig, SmpTransaction
規則2 方法名使用類意義完整的英文描述:第一個單詞的字母使用小寫、剩餘單詞首字母大寫其餘字母小寫的大小寫混合法。
示例:
privatevoid calculateRate();
publicvoid addNewOrder();
規則3 方法中,存取屬性的方法採用setter 和 getter方法,動作方法採用動詞和動賓結構。
格式:
get + 非布爾屬性名()
is + 布爾屬性名()
set + 屬性名()
動詞()
動詞 + 賓語()
示例:
publicString getType();
publicboolean isFinished();
publicvoid setVisible(boolean);
publicvoid show();
publicvoid addKeyListener(Listener);
規則4 屬性名使用意義完整的英文描述,第一個單詞的字母使用小寫,剩餘單詞首字母大寫其餘字母小寫的大小寫混合法。屬性名不能與方法名相同。
示例:
privatecustomerName;
privateorderNumber;
privatesmpSession;
規則5 常量名使用全大寫的英文描述,英文單詞之間用下劃線分隔開,並且使用 static final修飾。
示例:
publicstatic final int MAX_VALUE = 1000;
publicstatic final String DEFAULT_START_DATE = “2001-12-08”;
1.3.2 建議
建議1 包名採用域後綴倒置的加上自定義的包名,採用小寫字母,都應該以com.huawei開頭(不包括一些特殊原因)。在部門內部應該規劃好包名的範圍,防止產生衝突。部門內部產品使用部門的名稱加上模塊名稱。產品線的產品使用產品的名稱加上模塊的名稱。
說明:除特殊原因包結構都必須以com.huawei開頭,如果因爲OEM合作等關係,可以不做要求。
格式:
com.huawei.產品名.模塊名稱
示例:
融合WEBSMAP包名 com.huawei.iin.websmap
建議2 通過對函數或過程、變量、結構等正確的命名以及合理地組織代碼的結構,使代碼成爲自注釋的。
說明:清晰準確的函數、變量等的命名,可增加代碼可讀性,並減少不必要的註釋。
建議3 常用組件類的命名以組件名加上組件類型名結尾。
示例:
Application 類型的,命名以App 結尾——MainApp
Frame 類型的,命名以Frame 結尾——TopoFrame
Panel 類型的,建議命名以Panel結尾——CreateCircuitPanel
Bean 類型的,建議命名以Bean 結尾——DataAccessBean
EJB 類型的,建議命名以EJB 結尾——DBProxyEJB
Applet 類型的,建議命名以Applet 結尾——PictureShowApplet
建議4 如果函數名超過15 個字母,可採用以去掉元音字母的方法或者以行業內約定俗成的縮寫方式縮寫函數名。
示例:
getCustomerInformation() 改爲 getCustomerInfo()
建議5 準確地確定成員函數的存取控制符號:只是該類內部調用的函數使用 private 屬性,繼承類可以使用的使用protected屬性,同包類可以調用的使用默認屬性(不加屬性控制符號),對外公開的函數使用public屬性
示例:
protected void getUserName()
{
。。。。。。
}
private void calculateRate()
{
。。。。。。
}
建議6 含有集合意義的屬性命名,儘量包含其複數的意義。
示例:
customers, orderItems
1.4 編碼
1.4.1 規則
規則1 數據庫操作、IO操作等需要使用結束close()的對象必須在try -catch-finally 的finally中close(),如果有多個IO對象需要close(),需要分別對每個對象的close()方法進行try-catch,防止一個IO對象關閉失敗其他IO對象都未關閉。
示例:
try
{
// ... ...
}
catch(IOExceptionioe)
{
//... ...
}
finally
{
try
{
out.close();
}
catch (IOException ioe)
{
//... ...
}
try
{
in.close();
}
catch (IOException ioe)
{
//... ...
}
}
規則2 系統非正常運行產生的異常捕獲後,如果不對該異常進行處理,則應該記錄日誌。
說明:此規則指通常的系統非正常運行產生的異常,不包括一些基於異常的設計。若有特殊原因必須用註釋加以說明。
示例:
try
{
//.... ...
}
catch(IOException ioe)
{
logger.error(ioe);
}
規則3 自己拋出的異常必須要填寫詳細的描述信息。
說明:便於問題定位。
示例:
thrownew IOException(“Writing dataerror! Data: ” + data.toString());
規則4 運行時異常使用RuntimeException的子類來表示,不用在可能拋出異常的方法聲明上加throws子句。非運行期異常是從Exception繼承而來的,必須在方法聲明上加throws子句。
說明:
非運行期異常是由外界運行環境決定異常拋出條件的異常,例如文件操作,可能受權限、磁盤空間大小的影響而失敗,這種異常是程序本身無法避免的,需要調用者明確考慮該異常出現時該如何處理方法,因此非運行期異常必須有throws子句標出,不標出或者調用者不捕獲該類型異常都會導致編譯失敗,從而防止程序員本身疏忽。
運行期異常是程序在運行過程中本身考慮不周導致的異常,例如傳入錯誤的參數等。拋出運行期異常的目的是防止異常擴散,導致定位困難。因此在做異常體系設計時要根據錯誤的性質合理選擇自定義異常的繼承關係。
還有一種異常是Error 繼承而來的,這種異常由虛擬機自己維護,表示發生了致命錯誤,程序無法繼續運行例如內存不足。我們自己的程序不應該捕獲這種異常,並且也不應該創建該種類型的異常。
規則5 在程序中使用異常處理還是使用錯誤返回碼處理,根據是否有利於程序結構來確定,並且異常和錯誤碼不應該混合使用,推薦使用異常。
說明:
一個系統或者模塊應該統一規劃異常類型和返回碼的含義。
但是不能用異常來做一般流程處理的方式,不要過多地使用異常,異常的處理效率比條件分支低,而且異常的跳轉流程難以預測。
注意:Java 5.0 程序內部的錯誤碼可以使用枚舉來表示。
規則6 注意運算符的優先級,並用括號明確表達式的操作順序,避免使用默認優先級。
說明:防止閱讀程序時產生誤解,防止因默認的優先級與設計思想不符而導致程序出錯。
示例:
下列語句中的表達式
word= (high << 8) | low (1)
if((a | b) && (a & c)) (2)
if((a | b) < (c & d)) (3)
如果書寫爲
high<< 8 | low
a | b&& a & c
a | b< c & d
(1)(2)雖然不會出錯,但語句不易理解;(3)造成了判斷條件出錯。
規則7 避免使用不易理解的數字,用有意義的標識來替代。涉及物理狀態或者含有物理意義的常量,不應直接使用數字,必須用有意義的靜態變量或者枚舉來代替。使用異常來表示方法執行錯誤,而不是使用C++的錯誤返回碼方式。
示例:如下的程序可讀性差。
if(state == 0)
{
state = 1;
... // program code
}
應改爲如下形式:
privatefinal static int TRUNK_IDLE = 0;
privatefinal static int TRUNK_BUSY = 1;
privatefinal static int TRUNK_UNKNOWN = -1;
if(state == TRUNK_IDLE)
{
state = TRUNK_BUSY;
... // program code
}
注意:Java5.0 下建議使用枚舉來表示。
異常:
publicvoid function()
{
…
throw new RuntimeException(“。。。”);
}
規則8 數組聲明的時候使用 int[] index ,而不要使用 int index[] 。
說明:使用int index[] 格式使程序的可讀性較差,int [] index 表示聲明瞭一個int數組(int [])叫做index
示例:
如下程序可讀性差:
publicint getIndex()[]
{
....
}
如下程序可讀性好:
publicint[] getIndex()
{
....
}
規則9 不要使用 System.out 與 System.err 進行控制檯打印,應該使用工具類(如:日誌工具)進行統一記錄或者打印。
說明:代碼發佈的時候可以統一關閉控制檯打印,代碼調試的時候又可以打開控制檯打印,方便調試。
規則10 用調測開關來切換軟件的DEBUG版和正式版,而不要同時存在正式版本和DEBUG版本的不同源文件,以減少維護的難度。
規則11 集合必須指定模板類型(5.0+)
說明:方便程序閱讀,除去強制轉換代碼
示例:
Map