Java編碼規範

1. 目的

本規範的目的是使本組織能以標準的、規範的方式設計和編碼。經過創建編碼規範,使每一個開發人員養成良好的編碼風格和習慣;並以此造成開發小組編碼約定,提升程序的可靠性、可讀性、可修改性、可維護性和一致性等,增進團隊間的交流,並保證軟件產品的質量。java

 

2. 適用範圍

本規範適用於XXXX有限公司技術部全部軟件開發人員,在整個軟件開發過程當中必須遵循此規範。程序員

 

3. 版權聲明

²  本文檔爲共享文檔,不限轉載,但請保持本文檔的完整性算法

²  您能夠修改本文檔以符合您或組織、公司等之實際,但請在文檔中保持對本文檔的引用和說明。shell

²  未經產品開發中心受權,任何我的、組織或單位不得將本文檔用於書面發表、轉載、摘錄等,亦不得用於其餘商業行爲。數據庫

²  本人及本組織不承擔任何因使用、參考本文檔等而致使的任何可能責任或連帶責任。express

 

4. 參考資料

²  《Java 編程指南》見RUP(Rational Unified Process)中文版。編程

²  《Java技術手冊》(Java in a Nutshell)設計模式

²  《Sun Java語言編碼規範》(Java Code Conventions)數組

²  《Effictive Java》安全

²  《Java Pitfalls》

²  《Java Rules》

 

5. 概述

對於代碼,首要要求是它必須正確,可以按照設計預約功能去運行;第二是要求代碼必須清晰易懂,使本身和其餘的程序員可以很容易地理解代碼所執行的功能等。然而,在實際開發中,每一個程序員所寫的代碼卻常常自成一套,不多統一,致使理解困難,影響團隊的開發效率及系統的質量等。所以,一份完整並被嚴格執行的開發規範是很是必須的,特別是對軟件公司的開發團隊而言。此規範參考自業界標準編程規範而制定。

最根本的原則:

²  代碼雖然是給機器運行的,但倒是給人讀的!

²  運用常識。當找不到任何規則或指導方針,當規則明顯不能適用,當全部的方法都失效的時侯:運用常識並覈實這些基本原則。這條規則比其它全部規則都重要。常識是必不可少。

²  當出現該狀況時,應當及時收集並提交,以便對本規範進行修改。

 

6. 代碼組織風格  

6.1.  基本原則

代碼的組織和風格的基本原則是:便於本身的開發,易於與他人的交流。

因我的習慣和編輯器等能夠設置和造成本身的風格,但必須先後一致,並符合本規範的基本要求和原則。

本章所涉及到的內容通常均可在Java集成編輯環境中進行相應設置,也可由Ant等調用checkstyle等來進行自動規整。

 

6.2.  縮進

子功能塊當在其父功能塊後縮進。

當功能塊過多而致使縮進過深時當將子功能塊提取出來作爲子函數。

代碼中以TAB(4個字符)縮進,在編輯器中請將TAB設置爲以空格替代,不然在不一樣編輯器或設置下會致使TAB長度不等而影響整個程序代碼的格式。例如:

Table1.縮進示例

public void methodName(){

if(some condition){

for(…){

//some sentences

}//end for

}//end if

}

 

6.3.  長度

爲便於閱讀和理解,單個函數的有效代碼長度當儘可能控制在100行之內(不包括註釋行),當一個功能模塊過大時每每形成閱讀困難,所以當使用子函數等將相應功能抽取出來,這也有利於提升代碼的重用度。

單個類也不宜過大,當出現此類狀況時當將相應功能的代碼重構到其餘類中,經過組合等方式來調用,建議單個類的長度包括註釋行不超過1500行。

儘可能避免使用大類和長方法。

 

6.4.  行寬

頁寬應該設置爲150字符。通常不要超過這個寬度, 這會致使在某些機器中沒法以一屏來完整顯示, 但這一設置也能夠靈活調整。在任何狀況下, 超長的語句應該在一個逗號後或一個操做符前折行。一條語句折行後, 應該比原來的語句再縮進一個TAB或4個空格,以便於閱讀。

 

6.5.  間隔

類、方法及功能塊間等應以空行相隔,以增長可讀性,但不得有無規則的大片空行。操做符兩端應當各空一個字符以增長可讀性。

相應獨立的功能模塊之間可以使用註釋行間隔,並標明相應內容,具體參看附錄的代碼示例。

 

6.6.  對齊

關係密切的行應對齊,對齊包括類型、修飾、名稱、參數等各部分對齊。

連續賦值時當對齊操做符。

當方法參數過多時當在每一個參數後(逗號後)換行並對齊。

當控制或循環中的條件比較長時當換行(操做符前)、對齊並註釋各條件。

變量定義最好經過添加空格造成對齊,同一類型的變量應放在一塊兒。以下例所示:

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. 註釋

7.   

7.1.  基本原則

²  註釋應該增長代碼的清晰度。代碼註釋的目的是要使代碼更易於被其餘開發人員等理解。

²  若是你的程序不值得註釋,那麼它極可能也不值得運行。

²  避免使用裝飾性內容。

²  保持註釋的簡潔。

²  註釋信息不只要包括代碼的功能,還應給出緣由。

²  不要爲註釋而註釋。

²  除變量定義等較短語句的註釋可用行尾註釋外,其餘註釋當避免使用行尾註釋。

 

7.2.  JavaDoc

對類、方法、變量等的註釋須要符合JavaDoc規範,對每一個類、方法都應詳細說明其功能、條件、參數等,並使用良好的HTML標記格式化註釋,以使生成的JavaDoc易閱讀和理解。

 

7.3.  文件註釋

在每一個文件的頭部都應該包含該文件的功能、做用、做者、版權以及建立、修改記錄等。並在其中使用SVN標記自動跟蹤版本變化及修改記錄等信息。注意是/**/註釋而不是/***/JavaDoc註釋。

Table3 文件(File)註釋模板

/*

 * Copyright (C) 2006-${year} 普信恆業科技發展(北京)有限公司.

 * 本系統是商用軟件,未經受權擅自複製或傳播本程序的部分或所有將是非法的.

============================================================

 * FileName: ${file_name}

 * Created: [${date} ${time}] by ${user}

 * $$Id$$

 * $$Revision$$

 * $$Author$$

 * $$Date$$

============================================================

 * ProjectName: ${project_name}

 * Description:

==========================================================*/

 

7.4.  類、接口註釋

在類、接口定義以前當對其進行註釋,包括類、接口的目的、做用、功能、繼承於何種父類,實現的接口、實現的算法、使用方法、示例程序等,在做者和版本域中使用SVN標記自動跟蹤版本變化等,具體參看註釋模板。

Table4 類(Types)註釋模板

/**

 * Description:

 * @author ${user}

 * @version 1.0

 * <pre>

 * Modification History:

 * Date         Author      Version     Description

------------------------------------------------------------------

 * ${date}    ${user}       1.0        1.0 Version

 * </pre>

 */

 

7.5.  方法註釋

依據標準JavaDoc規範對方法進行註釋,以明確該方法功能、做用、各參數含義以及返回值等。複雜的算法用/**/在方法內註解出。

參數註釋時當註明其取值範圍等

返回值當註釋出失敗、錯誤、異常時的返回狀況。

異常當註釋出什麼狀況、何時、什麼條件下會引起什麼樣的異常。

Table5 方法(Methods)註釋模板

/**

 * Description:

 * @param

 * @return ${return_type}

 * @throws

 * @Author ${user}

 * Create Date: ${date} ${time}

 */

 

7.6.  其餘註釋

應對重要的變量加以註釋,以說明其含義等。

應對不易理解的分支條件表達式加註釋。不易理解的循環,應說明出口條件。過長的方法實現,應將其語句按實現的功能分段加以歸納性說明。

對於異常處理當註明正常狀況及異常狀況或者條件,並說明當異常發生時程序當如何處理。

 

7.7.  註釋參考表

Table6 註釋參考表

項目

註釋內容

參數

參數類型

參數用來作什麼

約束或前提條件

示例

字段/屬性

字段描述

註釋全部使用的不變量

示例

並行事件

可見性決策

類的目的

已知的問題

類的開發/維護歷史、版本

註釋出採用的不變量

並行策略

編譯單元

(文件)

每個類/類內定義的接口,含簡單的說明

文件名和/或標識信息

修改/維護記錄

版權信息

獲取成員函數

若可能,說明爲何使用滯後初始化

接口

目的

它應如何被使用以及如何不被使用

局部變量

用處/目的

成員函數註釋

成員函數作什麼以及它爲何作這個

哪些參數必須傳遞給一個成員函數

成員函數返回什麼

已知的問題

任何由某個成員函數拋出的異常

可見性決策

成員函數是如何改變對象的

包含任何修改代碼的歷史

如何在適當狀況下調用成員函數的例子

適用的前提條件和後置條件

成員函數內部註釋

控制結構

代碼作了些什麼以及爲何這樣作

局部變量

 

難或複雜的代碼處理順序

包的功能和用途

 

8. 命名

8.   

8.1.  基本原則

規範的命名能使程序更易閱讀,從而更易於理解。它們也能夠提供一些標識功能方面的信息,有助於更好的理解代碼和應用。

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。

 

8.2.  文件、包

1)    文件名當與其類嚴格相同,全部單詞首字母大寫。

2)    包名通常以項目或模塊名命名,少用縮寫和長名,一概小寫。

3)    基本包:org.skyinn,全部包、文件都從屬於此包。

4)    包名按以下規則組成:

[基本包].[項目名].[模塊名].[子模塊名]...

如:

org.skyinn.quasar

org.skyinn.skyhome.dao.hibernate

5)    不得將類直接定義在基本包下,全部項目中的類、接口等都當定義在各自的項目和模塊包中。

6)    自主開發程序的命名規則爲:com.creditease.XXXX

 

8.3.  類、接口

全部單詞首字母大寫。使用能確切反應該類、接口含義、功能等的詞。通常採用名詞。

接口文件名前添加大寫字母「I」,其後使用able。

 

8.4.  字段

8.4.1.  常量

採用完整的英文大寫單詞,在詞與詞之間用下劃線鏈接,如:DEFAULT_VALUE。

 

8.4.2.  變量和參數

對不易清楚識別出該變量類型的變量應使用類型縮寫做其前綴,如字符串使用strXXX,boolean使用isXXX,hasXXX等等。除第一各個單詞外其他單詞首字母大寫。

對私有實例變量可以使用_前綴,但在其存取方法中則應該將其前綴去掉。

 

8.4.3.  組件/部件

應採用完整的英文描述符命名組件(接口部件),遵循匈牙利命名法則。

如:btnOK,lblName。

 

8.4.4.  集合

一個集合,例如數組和矢量,應採用複數命名來表示隊列中存放的對象類型。命名應採用完整的英文描述符,名字中全部非開頭的單詞的第一個字母應大寫,適當使用集合縮寫前綴。如:

Vector vProducts = new Vector(); //產品向量

Array aryUsers = new Array(); //用戶列表

 

8.4.5.  神祕的數

咱們在程序裏常常會用到一些量,它是有特定的含義的。例如,如今咱們寫一個薪金統計程序,公司員工有50人,咱們在程序裏就會用50這個數去進行各類各樣的運算。在這裏,50就是"神祕的數"。當別的程序員在程序裏看到50這個數,將很難知道它的含義,形成理解上的困難。

在程序裏出現"神祕的數"會下降程序的可讀性、可維護性和可擴展性,故規定不得出現此類"神祕的數"。避免的方法是把神祕的數定義爲一個常量。注意這個常量的命名應該能表達該數的意義,而且應該所有大寫,以與對應於變量的標識符區別開來。例如上面50這個數,咱們能夠定義爲一個名爲NUM_OF_EMPLOYEES的常量來代替。這樣,別的程序員在讀程序的時候就能夠容易理解了。

 

8.4.6.  其餘

命名時應使用複數來表示它們表明多值。如:orderItems。

 

8.5.  方法

方法的命名應採用完整的英文描述符,大小寫混合使用:全部中間單詞的第一個字母大寫。方法名稱的第一個單詞經常採用一個有強烈動做色彩的動詞。

取值類使用get前綴,設值類使用set前綴,判斷類使用is(has)前綴。

例: getName()

setSarry()

isLogon()

方法參數建議順序:(被操做者,操做內容,操做標誌,其餘⋯)

例:public void replace(String sourceStr, //源字串

String oldStr, //被替換字串

String newStr){ //替換爲字串

 

8.6.  異常

異常類名由表示該異常類型的單詞和Exception組成,如ActionException。

異常實例通常使用e、ex等,在多個異常時使用該異常名或簡寫加E,Ex等組成,如:

SQLEx

ActionEx

 

8.7.  命名約定表

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. 聲明

9.   

9.1.  基本原則

聲明的基本原則是遵照Java語言規範,並聽從習慣用法。

 

9.2.  包

在導入包時當徹底限制代碼所使用的類的名字,儘可能少用通配符的方式,但導入一些通用包,或用到一個包下大部分類時,則但是使用通配符方式,如:

import org.skyinn.quasar.services.Service;

import java.util.*;

同一包中的類導入時當聲明在一塊兒,可由編輯器自動完成此功能。

重要的包當添加註釋。

 

9.3.  類、接口

類、接口定義語法規範:

[可見性][('abstract'|'final')] [Class|Interface] class_name

[('extends'|'implements')][父類或接口名]{

}

如:

public class LoginAction extends BaseAction implemnets ActionListener {

}

 

9.4.  方法

良好的程序設計應該儘量減少類與類之間耦合,所遵循的經驗法則是:儘可能限制成員函數的可見性。若是成員函數不必公有 (public),就定義爲保護 (protected);不必保護 (protected),就定義爲私有 (private)。

方法定義語法規範:

[可見性][('abstract'|'final')] ['synchronized'][返回值類型] method_name(參數列表)[('throws')][異常列表]{

// 功能模塊

}

 

如:

public List listAllUsers() throws DAOException{}

如有toString(),equals(),hashCode(),colone()等重載自Object的方法,應將其放在類的最後。

聲明順序:

構造方法

靜態公共方法

靜態私有方法

受保護方法

私有方法

繼承自Object的方法

 

9.5.  字段

字段定義語法規範:

[(‘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); //不要用這種數組聲明方式

一行代碼只聲明一個變量,僅將一個變量用於一件事。

聲明順序:

常量

類變量

實例變量

公有字段

受保護字段

私有字段

能夠將私有變量聲明在類或接口的最後。

注意受保護變量、私有變量、「包」變量間的區別。

 

9.6.  示例

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.    類與接口

10.     

10.1.    基本原則

類的劃分粒度,不可太大,形成過於龐大的單個類,也不可太細,從而使類的繼承太深。通常而言,一個類只作一件事;另外一個原則是根據每一個類的職責進行劃分,好比用User來存放用戶信息,而用UserDAO來對用戶信息進行數據訪問操做(好比存取數據庫),用UserBroker來封裝用戶信息的業務操做等等。

多使用設計模式,隨時重構。

多個類中使用相同方法時將其方法提到一個接口中或使用抽象類,儘可能提升重用度。

將不但願再被繼承的類聲明成final,例如某些實用類,但不要濫用final,不然會對系統的可擴展性形成影響。

將不但願被實例化的類的缺省構造方法聲明成private。

 

10.2.    抽象類與接口

通常而言:接口定義行爲,而抽象類定義屬性和公有行爲,注意二者間的取捨,在設計中,可由接口定義公用的行爲,由一個抽象類來實現其部分或所有方法,以給子類提供統一的行爲定義,可參考Java集合等實現。

多使用接口,儘可能作到面向接口的設計,以提升系統的可擴展性。

 

10.3.    繼承與組合

儘可能使用組合來代替繼承,一則可使類的層次不至於過深,並且會使類與類,包與包之間的耦合度更小,更具可擴展性。

 

10.4.    構造函數和靜態工廠方法

當須要使用多個構造函數建立類時,建議使用靜態工廠方法替代這些構造方法(參考《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)...

 

10.5.    toString( ),equals( ),hashCode( )...

每一個類都應該重載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):

 

10.6.    Singleton Class

單例類使用以下方式聲明,並將其缺省構造方法聲明成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.    方法

11.     

11.1.    基本原則

一個方法只完成一項功能,在定義系統的公用接口方法外的方法應儘量的縮小其可見性。

避免用一個類是實例去訪問其靜態變量和方法。

避免在一個較長的方法裏提供多個出口:

//不要使用這鐘方式,當處理程序段很長時將很難找到出口點

if(condition){

return A;

}else{

return B;

}

//建議使用以下方式

String result = null;

if(condition){

result = A;

}else{

result = B;

}

return result;

 

11.2.    參數和返回值

避免過多的參數列表,儘可能控制在5個之內,若須要傳遞多個參數時,當使用一個容納這些參數的對象進行傳遞,以提升程序的可讀性和可擴展性。

參數類型和返回值儘可能接口化,以屏蔽具體的實現細節,提升系統的可擴展性,例如:

public void joinGroup(List userList){}

public List listAllUsers(){}

 

12.    表達式與語句

12.     

12.1.    基本原則

表達式和語句當清晰、簡潔,易於閱讀和理解,避免使用晦澀難懂的語句。

每行至多包含一條執行語句,過長當換行。

避免在構造方法中執行大量耗時的初始化工做,應當將這中工做延遲到被使用時再建立相應資源,若是不可避免,則當使用對象池和Cache等技術提升系統性能。

避免在一個語句中給多個變量賦相同的值。它很難讀懂。

不要使用內嵌(embedded)賦值運算符試圖提升運行時的效率,這是編譯器的工做。

儘可能在聲明局部變量的同時初始化。惟一不這麼作的理由是變量的初始值依賴於某些先前發生的計算。

通常而言,在含有多種運算符的表達式中使用圓括號來避免運算符優先級問題,是個好方法。即便運算符的優先級對你而言可能很清楚,但對其餘人未必如此。你不能假設別的程序員和你同樣清楚運算符的優先級。

不要爲了表現編程技巧而過度使用技巧,簡單就好。

 

12.2.    控制語句

判斷中若有常量,則應將常量置與判斷式的左側。如:

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

12.3.    循環語句

循環中必須有終止循環的條件或語句,避免死循環。

當在for語句的初始化或更新子句中使用逗號時,避免因使用三個以上變量,而致使複雜度提升。若須要,能夠在for循環以前(爲初始化子句)或for循環末尾(爲更新子句)使用單獨的語句。

由於循環條件在每次循環中多會執行一次,故儘可能避免在其中調用耗時或費資源的操做,比較一下兩種循環的差別:

//不推薦方式____________________________________________

while(index < products.getCount()){

//每此都會執行一次getCount()方法,

//若此方法耗時則會影響執行效率

//並且可能帶來同步問題,如有同步需求,請使用同步塊或同步方法

}

//推薦方式______________________________________________

//將操做結構保存在臨時變量裏,減小方法調用次數

final int count = products.getCount();

while(index < count){ }

 

13.    錯誤與異常

13.     

13.1.    基本原則

一般的思想是隻對錯誤採用異常處理:邏輯和編程錯誤,設置錯誤,被破壞的數據,資源耗盡,等等。

一般的法則是系統在正常狀態下以及無重載和硬件失效狀態下,不該產生任何異常。

最小化從一個給定的抽象類中導出的異常的個數。

對於常常發生的可預計事件不要採用異常。

不要使用異常實現控制結構。

確保狀態碼有一個正確值。

在本地進行安全性檢查,而不是讓用戶去作。

如有finally子句,則不要在try塊中直接返回,亦不要在finally中直接返回。

 

13.2.    已檢查異常與運行時異常

已檢查異常必須捕捉並作相應處理,不能將已檢查異常拋到系統以外去處理。

對可預見的運行時異常當進行捕捉並處理,好比空指針等。一般,對空指針的判斷不是使用捕捉NullPointException的方式,而是在調用該對象以前使用判斷語句進行直接判斷,如:

//若不對list是否爲null進行檢查,則在其爲null時會拋出空指針異常

if(null != list && 0 < list.size()){

for(int i = 0; i < list.size(); i++){

}

}

建議使用運行時異常(RuntimeException)代替已檢查異常(CheckedException),請參考網絡資源以對此兩種異常作更深刻理解。

 

13.3.    異常的捕捉與處理

捕捉異常是爲了處理它,不要捕捉了卻什麼都不處理而拋棄之,最低限度當向控制檯輸出當前異常,若是你不想處理它,請將該異常拋給它的調用者,建議對每一個捕捉到的異常都調用printStackTrace()輸出異常信息,避免因異常的湮沒。

多個異常應分別捕捉並處理,避免使用一個單一的catch來處理。如:

try {

//do something

}catch(IllegalStateException IllEx){

IllEx.printStackTrace();

//deal with IllEx

}catch(SQLException SQLEx){

SQLEx.printStackTrace();

throw SQLEx; //拋給調用者處理

}finally{

//釋放資源

}

 

14.    測試與Bug跟蹤

14.     

14.1.    基本原則

測試不經過的代碼不得提交到SVN庫或者發佈。

不得隱瞞、忽略、繞過任何Bug,有Bug不必定是你的錯,但有了Bug不做爲就是你的不對了。

多作測試,測試要徹底,儘可能將各類可能狀況都測試經過,儘可能將可能的Bug在開發中捕捉並處理掉。

測試要保證可再測試性。

測試應當對數據庫等資源不留或少留痕跡,例如,當測試添加一個用戶時,在其成功後當及時從數據庫中刪除該記錄,以免髒數據的產生(由此衍生的一個經驗是將添加、獲取、刪除一塊兒測試)。

對關鍵功能必須測試並經過,對輔助功能及很是簡單之功能可不作測試。

 

14.2.    Junit單元測試

在Java應用中,單元測試使用Junit及其衍生工具。

在TestCase的setUp()中初始化應用,在tearDown()中釋放資源。可由一個基礎TestCase完成這些任務,其餘TestCase繼承之。

 

14.3.    持續集成

由持續集成工具來完成代碼編譯與自動部署,參見《持續集成規程》。

 

14.4.    Bug跟蹤和缺陷處理

當系統出現Bug時當由該Bug的負責人(代碼負責人)儘快修改之。

Bug的處理根據其優先級高低和級別高低前後處理。

Bug級別和優先級別參見《軟件測試規程》。

禁止隱瞞Bug。

 

15.    性能與安全

15.     

15.1.    基本原則

性能的提高並非一蹴而就的,而是由良好的編程積累的,雖然任何良好的習慣和經驗所提高的性能都十分有限,甚至微乎其微,但良好的系統性能倒是由這些習慣等積累而成,不積細流,無以成江海!

 

15.2.    String與StringBugffer

不要使用以下String初始化方法:

String str = new String(「abcdef」);

這將產生兩個對象,應當直接賦值:

String str = 「abcdef」;

在處理可變 String 的時候要儘可能使用 StringBuffer 類,StringBuffer 類是構成 String 類的基礎。String 類將 StringBuffer 類封裝了起來,(以花費更多時間爲代價)爲開發人員提供了一個安全的接口。當咱們在構造字符串的時候,咱們應該用 StringBuffer 來實現大部分的工做,當工做完成後將 StringBuffer 對象再轉換爲須要的 String 對象。好比:若是有一個字符串必須不斷地在其後添加許多字符來完成構造,那麼咱們應該使用 StringBuffer 對象及其 append() 方法。若是咱們用 String 對象代替 StringBuffer 對象的話,將會花費許多沒必要要的建立和釋放對象的 CPU 時間。

 

15.3.    集合

避免使用Vector和HashTable等舊的集合實現,這些實現的存在僅是爲了與舊的系統兼容,並且因爲這些實現是同步的,故而在大量操做時會帶來沒必要要的性能損失。在新的系統設計中不當出現這些實現,使用ArrayList代替Vector,使用HashMap代替HashTable。

若倒是須要使用同步集合類,當使用以下方式得到同步集合實例:

Map map = Collections.synchronizedMap(new HashMap());

因爲數組、ArrayList與Vector之間的性能差別巨大(具體參見《Java fitball》),故在能使用數組時不要使用ArrayList,儘可能避免使用Vector。

 

15.4.    對象

避免在循環中頻繁構建和釋放對象。

再也不使用的對象應及時銷燬。

如無必要,不要序列化對象。

 

15.5.    同步

在不須要同步操做時避免使用同步操做類,如能使用ArrayList時不要使用Vector。

儘可能少用同步方法,避免使用太多的 synchronized 關鍵字。

儘可能將同步最小化,即將同步做用到最須要的地方,避免大塊的同步塊或方法等。

 

15.6.    final

將參數或方法聲明成final可提升程序響應效率,故此:

注意絕對不要僅由於性能而將類、方法等聲明成final,聲明成final的類、方法必定要確信再也不被繼承或重載!

不須要從新賦值的變量(包括類變量、實例變量、局部變量)聲明成final

全部方法參數聲明成final

私有(private)方法不須要聲明成final,若方法肯定不會被繼承,則聲明成final。

 

15.7.    垃圾收集和資源釋放

不要過度依賴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.    持久層

16.     

16.1.    數據庫主鍵生成策略

主鍵類型:

字符串/整型值。推薦使用字符型作主鍵,如有性能要求,容許使用數值類型

生成機制:

字符串:生成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

相關文章
相關標籤/搜索