目 錄 java
1. 序言 4 git
2. 範圍 4 算法
3. 代碼命名的通常原則 4 數據庫
4. 代碼註釋的通常原則和類型 4 express
5.3. 成員方法的頭部註釋文檔規範 6 性能優化
本規範的目的在於編寫出可靠的,一致的,便於理解的JAVA源代碼,而且寫出的代碼容易被其餘人閱讀,全部的JAVA代碼保持良好的一致性,容易在之後的階段中進行維護和升級。同時,也是爲了經過必定時間的實踐,增長軟件產品的投入產出量,以提升工做效率。
在JAVA代碼中,全部的代碼命名的總原則是:
在JAVA代碼中,咱們常常要使用代碼註釋的方式來幫助理解代碼的含義。代碼註釋的通常原則主要有如下幾個方面:
在JAVA代碼中,常用三種類型的註釋:文檔型的註釋,其通常格式是:以"/**"開頭,以"*/"結尾; C語言類型的註釋,它一般是以"/*"開頭,以"*/"結尾;還有一種是一般用的單行註釋的方法,即以"//"開頭,對一個單行進行註釋。下面以表格的方式,分別說明這三種方式在JAVA中如何更好的使用。
註釋類型 |
使用方式 |
例程 |
文檔型註釋 |
文檔型註釋常常用在定義接口,類,成員方法,域的定義以前,而且這種註釋能夠被經過javadoc直接生成幫助文檔。 |
/** Customer- A customer is any person or …… @author S.W.Ambler */ public class Customer{} |
C風格型的註釋 |
當要一次對多行代碼進行註釋,或者這些代碼將不被執行,或者對這些行進行調試時,本註釋是一種比較合適的註釋方法。 |
/* This code was commented .. ………… ……(the source code) */ |
單行註釋 |
一般在成員方法內部註釋商業邏輯,一小節代碼,或者臨時變量的聲明。 |
//Apply a 5% discount to all //invoices over $1000 as //defined by the ….. |
同時,爲了編程人員所作的文檔型註釋,能更有效的生成HTML格式的幫助文件,將提供如下一些更多的內容:
標誌 |
使用 |
目的 |
@author authorName |
通常在類、接口定義以前的文檔型註釋裏面使用。 |
通常是指明編寫本接口或本類的做者,固然能夠有多個,每個做者用@author標明。 |
@deprecated |
通常在類,成員方法定義以前的文檔型註釋裏面使用。 |
它通常用於聲明一個類或者一個成員方法被廢棄,再也不使用。 |
@exception name description |
成員方法定義以前的文檔型註釋裏面使用。 |
用於聲明本成員方法將可能會拋出的異常。每個異經常使用一個@exception標明。 |
@param name description |
成員方法定義以前的文檔型註釋裏面使用。 |
用於說明傳遞給該成員方法的參數,包括其類型和它的使用,每個參數用@param標明。 |
@return description |
成員方法定義以前的文檔型註釋裏面使用。 |
用於說明本成員方法的返回值類型,若是可能,適當的描述其可能的返回值 |
@see ClassName |
通常在類,接口,成員方法,域定義以前的文檔型註釋裏面使用。 |
用於創建一個超文本連接到指定的類,接口。通常應該詳細的描述其類名。 |
@see ClassName#member functionsName |
通常在類,接口,成員方法,域定義以前的文檔型註釋裏面使用。 |
用於創建一個超文本連接到指定的成員方法。通常應詳細描述類名。 |
@version text |
通常在類,接口定義以前的文檔型註釋裏使用。 |
用於指定相應的版本信息。 |
成員方法的命名應該採用全英文單詞且是大小寫混合的方式來進行。方法名的第一個單詞均小寫,其它單詞的首字母大寫。並且方法名中第一個單詞最好是一個動詞形式的。如:openAccount() , printMailingLabel() , save() , delete() 等。
經過這樣的命名規範,很容易看出這個方法是幹什麼用的,它的目的是什麼。儘管有時方法名會比較長,但它能很容易讓其餘人理解本方法的意圖。
get方法,它通常返回一個屬性值,通常應將get放在方法名中第一個單詞的位置。而當它返回的是判斷其結果是true或者false的時候,通常用"is"來取代"get"。例如:getFirstName() , getAccountNumber() , isPersistent() , isAtEnd() 等等。
經過這種命名規範,就能夠很清楚的知道本方法是返回一個對象的屬性或返回一個boolean值。
一樣,對於set方法,它通常是用於設置對象的屬性值,一樣也將set放在方法名中的第一個單詞的位置。如:setFirstName(String aName), setAtEnd(boolean isAtEnd), setPersistent(boolean isPersistent)等等。
構造方法通常是用來建立一個對象時要執行的初始化操做。構造方法必須具備與類名徹底一致的名字,其大小寫也必須徹底一致。這種命名規範是由sun公司肯定,且必須遵照。
每個成員方法的前面必需要有相應的註釋文檔說明,它主要包括如下內容,但不只限於如下內容:
爲了更好的描述成員方法的目的,還會在成員方法的內部給予適當的註釋,通常有兩種格式:/*……..*/和//……….。通常而言,內部註釋文檔應該說明如下一些要素:
成員方法的訪問權限控制的基本原則是儘可能的限制對成員方法的訪問權限。若是沒有必要設置爲public,則將其設置爲protected,不然設置爲默認方式或者private。
getXxxx方法和setXxxx方法的名稱通常是: get + 屬性名/ set + 屬性名 或 is +屬性名。 例如:
屬性名 |
類型 |
get方法 |
set方法 |
FirstName |
String |
getFirstName() |
setFirstName(參數表) |
Persistent |
Boolean |
isPersistent() |
setPersistent(參數表) |
OrderItems |
Array of OrderItems Objects |
getOrderItems() |
setOrderItems(參數表) |
getXxxx方法和setXxxx方法通常對其有以下的使用方式:
// Answer the branch number, which is the leftmost four digits of the full account number
protected int getBranchNumber(){
if (branchNumber = = 0){
//The default branch number is 1000,which is the main branch in downtown Bedrock
setBranchNumber(1000);
}
return branchNumber;
}
getXxxx方法和setXxxx方法的訪問權限的控制:
通常狀況,將它們設置爲"protected",這樣,只有同包類或子類的對象能夠訪問它們。可是一般將getXxxx方法設置爲"public"方式,而setXxxx方法則是"protected"方式。只有在極少數狀況下才將setXxxx方法設置爲"public"方式。固然,有時也將setXxxx方法設置爲"private"方式。
屬性變量的命名採用全英文單詞的混合命名方式,第一個單詞所有小寫,之後單詞的
第一個字母大寫,其他小寫。以便讓它易於理解。而對於那些像數組或動態數組等一些多值的數據類型屬性,則應該採用單詞複數的方式命名(s加在最後一個單詞上面),它的主要優勢是能夠方便的指明它們有多個值。例如: firstName, zipCode, orderItems等。
爲了使對象具備更好的封閉性,通常不把屬性的訪問權限設置爲public,建議通常把全部的屬性訪問權限設置爲private,以防止其它類的對象直接訪問本類對象的屬性。而對屬性的訪問能夠用getXxxx方法和setXxxx方法進行。
每個屬性變量都要給予註釋,以便其餘開發人員更好的理解其含義。通常從如下幾個方面給予註釋:
對於組件的命名,通常採用全英文單詞的命名方式,可是採用將組件類型名做爲後綴的方法。這樣,就很容易識別這個組件變量的目的,從它的後綴類型就能夠方便的看出。也很容易在列表中找到每個組件(在不少可視化編程環境中,提供列表的方式來快速顯示全部用到的組件變量)。如: okJButton, fileJMenu, newFileMenuItem等等。
常量命名採用全英文單詞的方式進行,且全是大寫的字母,單詞之間用下劃線鏈接。如:MINIMUM_BALANCE, DEFAULT_START_DATE等等。 它的主要優勢是能夠很容易的與變量區分開來。
通常而言,局部變量的命名規範遵循屬性變量的命名規範,即全用英文單詞命名,且除第一個單詞之外,其它單詞的首字母均大寫。
可是,對於下面所列舉的幾種特殊類型的局部變量的命名有些特殊的規定:
1.streams
當一個單一的輸入或輸出流對象被定義和使用時,通常用in,inputStream表示輸入流,而用out,outputStream表示輸出流。而當一個流同時被使用爲輸入流和輸出流的時候,則用inOut或者ioStream來命名。
2.循環計數器的使用
因爲在成員方法中,咱們常常會用一些循環結構,同時也就會使用循環計數器。在之前的C,C++中,已經習慣於使用像i,j,k等變量做爲循環計數器,在JAVA編碼中,也採用經常使用的,單一的小寫字母來命名循環計數器。例如:for(i=0;i<10;i++)
3.異常對象的命名規範
在JAVA中,常常會碰到一些例外狀況的處理,通常用一個字母"e"來命名相應的例外對象,如存在多個異常則採用屬性的命名方式。
局部變量的文檔註釋通常涉及到如下幾個方面:
成員方法參數的命名規範基本上與局部變量的命名規範相同。 如: customer, inventoryItem, in , e等。
成員方法參數的文檔註釋:
成員方法參數的文檔註釋在成員方法的頭部註釋文檔中,它應包括如下內容:
類的命名也是採用全英文單詞描述的方法,但它的第一個單詞的首字母必須大寫,其它單詞的首字母也要大寫。例如: public class Customer{….} public class OrderItems{…}
類的註釋文檔通常位於類的定義以前,它將包含以下內容:
接口的命名,其第一個字母必須是大寫的"I",以代表它是一個接口,與其它類進行區別。剩下的部分與類的命名規範同樣,採用全英文單詞描述的方法,第一個單詞首字母大寫,其它單詞的首字母也大寫。例如:public interface IOrderItems{……..}
public interface ICustomer{…..}
接口的文檔註釋必須在接口被定義前給予說明,主要包括如下內容:
3.接口內的抽象成員方法的註釋,參照類的成員方法的註釋。
包的命名有如下幾個規則:
對於每個包,應該有一個或多個外部文檔來描述這個包。通常而言,文檔中應描述以下內容:
程序應以縮進形式展示程序的塊結構和控制結構,在不影響展現程序結構的前提下儘量地減小縮進的層次。採用以下兩種縮進方式之一:
1) |
if (expression ){ statements }else{ statements } |
一個程序的寬度若是超出頁寬或屏寬,這將是很難讀的,因此本規範要求使用折行縮進的方法、合併表達式或編寫子程序的方法來限制程序的寬度。
1)任何一個程序最大行寬不得超過80列,超過者應折行書寫。
2)建議一個函數的縮進不得超過5級,超過者應將其子塊寫爲子函數;
3)算法或程序自己的特性有特殊要求時,能夠超過5級。
性能優化的原則是先讓程序運行起來,再考慮變得更快——但只有在本身必須這樣作、並且經證明在某部分代碼中的確存在一個性能瓶頸的時候,才應進行優化。進行優化時需使用專門的工具分析瓶頸。須要注意的是性能提高的隱含代價是本身的代碼變得難於理解,並且難於維護。
對於像字符串的鏈接操做不使用"+"而使用專有方法 concat等其餘方法,這類問題,則不能稱爲性能優化,而只能叫作基本常識。這類問題的解決注意不能影響程序的可讀性和易維護性,如下是常見優化常識:
詳見表9-1運算時間。
表 9-1 運算時間
運算 |
示例 |
標準時間 |
本地賦值 |
i=n; |
1.0 |
實例賦值 |
this.i=n; |
1.2 |
Int增值 |
i++; |
1.5 |
Byte增值 |
b++; |
2.0 |
Short增值 |
s++; |
2.0 |
Float增值 |
f++; |
2.0 |
Double增值 |
d++; |
2.0 |
空循環 |
while(true) n++; |
2.0 |
三元表達式 |
(x<0)?-x:x; |
2.2 |
算術調用 |
Math.abs(x); |
2.5 |
數組賦值 |
a[0]=n; |
2.7 |
Long增值 |
l++; |
3.5 |
方法調用 |
funct(); |
5.9 |
Throw 或者catch 違例 |
Try{throw e;} |
320 |
同步方法調用 |
synchMethod(); |
570 |
新建對象 |
new Object(); |
980 |
新建數組 |
new int[10]; |
3100 |
字串的開銷:字串鏈接運算符"+"看似簡單,但實際須要消耗大量系統資源。編譯器可高效地鏈接字串,但變量字串卻要求可觀的處理器時間。該操做要建立並拆除一個StringBuffer對象以及一個String對象。
上述問題的一般解決方法是新建一個StringBuffer(字串緩衝),用append方法追加自變量,而後用toString()將結果轉換回一個字串。當要追加多個字串,則可考慮直接使用一個字串緩衝——特別是能在一個循環裏重複利用它的時候。經過在每次循環裏禁止新建一個字串緩衝,可節省980單位的對象建立時間(見表9-1)。
更有效的解決辦法是:在構造 StringBuffer 時,應該粗略的估計出它最終的總長度。默認構造函數預設了16個字符的緩存容量。append()方法首先計算字符串追加完成後的總長度,若是這個總長度大於StringBuffer的存儲能力,append()方法調用私有的expandCapacity()方法。expandCapacity()方法在每次被調用時使StringBuffer存儲能力加倍,並把現有的字符數組內容複製到新的存儲空間。存儲能力的擴展,從而致使了兩次代價昂貴的複製操做。所以,咱們至少有一點能夠作得比編譯器更好,這就是分配一個初始存儲容量大於或者等於最終字符長度StringBuffer。
所以,使用默認構造函數建立的StringBuffer在字符串鏈接操做上的效率其實和用"+"是同樣的。若是首先估計出整個字符串最終的總長度,纔會顯著提升效率!
其餘的字符串運算操做盡量使用 String 已經提供的方法。好比,短字符串的鏈接可使用 concat;子串的查找可使用 indexOf,substring 等。
一個Vector就是一個java.lang.Object實例的數組。Vector與數組類似,它的元素能夠經過整數形式的索引訪問。可是,Vector類型的對象在建立以後,對象的大小可以根據元素的增長或者刪除而擴展、縮小。
(1)避免把新元素添加到Vector 的最前面
(2)避免從中間刪除元素
(3)刪除全部元素的最好方法是 removeAllElements()
(4)避免二次搜索
Vector類型的對象v包含字符串"Hello"。考慮下面的代碼,它要從這個Vector中刪除"Hello"字符串:
String s = "Hello";
int i = v.indexOf(s);
if(i != -1)
v.remove(s);
在這段代碼中,indexOf()方法對v進行順序搜索尋找字符串"Hello",remove(s)方法也要進行一樣的順序搜索。改進以後的版本是:
String s = "Hello";
int i = v.indexOf(s);
if(i!= -1) v.remove(i);
這個版本中咱們直接在remove()方法中給出待刪除元素的精確索引位置,從而避免了第二次搜索。一個更好的版本是:
String s = "Hello";
v.remove(s);
循環內部的代碼不會以任何方式修改Vector類型對象大小時,應該提早取得Vector.size()
沒必要要的同步經常會形成程序性能的降低。所以,若是程序是單線程,則必定不要使用同步。
對某個方法或函數進行同步比對整個代碼段進行同步的性能要好。由於代碼段的同步牽涉的範圍比對某個方法或函數進行同步廣。
通常每一個對象都只有一個"鎖",這就代表若是兩個線程執行一個對象的兩個不一樣的同步方法時,會發生"死鎖"。即便這兩個方法並不共享任何資源。爲了不這個問題,能夠對一個對象實行"多鎖"的機制。
循環的邊界是指完成全部循環操做的起點和終點。若是循環體內的操做不影響邊界,那麼應該在循環體外,計算而且求得邊界值。例如:
for(int i = 0; i < array.length; i++)
{
array[i]=i;
}
上述代碼中每次循環操做,都要計算一次 array.length。
若是在循環體內用到新對象,須要在循環體開始之前構建好該對象。由標準時間表能夠看出構建對象有很大的系統消耗,而且在一次循環中還要清除掉該對象,下循環再從新構建。
遍歷數組、集合時,若是知足條件的元素找到,必定要使用 break 語句退出循環。