程式碼書寫規範(Java) (轉)

worldblog發表於2008-01-06
程式碼書寫規範(Java) (轉)[@more@]

  前幾天整理出來的一個的程式碼書寫規範!

程式碼書寫規範


一、目的 

  對於程式碼,首要要求是它必須正確,能夠按照員的真實思想去執行;第二個的要求是程式碼必須清晰易懂,使別的程式設計師能夠容易理解程式碼所進行的實際工作。在工程領域,源程式的風格統一標誌著可維護性、可讀性,是軟體專案的一個重要組成部分。而目前還沒有成文的編碼風格文件,以致於很多時候,程式設計師沒有一個共同的標準可以遵守,編碼風格各異,程式可維護性差、可讀性也很差。透過建立程式碼編寫規範,形成開發小組編碼約定,提高程式的可靠性、可讀性、可修改性、可維護性、可繼承性和一致性,可以保證程式程式碼的質量,繼承成果,充分利用資源,使開發人員之間的工作成果可以共享。

  本文在參考業界已有的編碼風格的基礎上,描述了一個基於 JBuilder 的專案風格,力求一種統一的風格,並從整體編碼風格、程式碼風格、編寫風格、變數風格、註釋風格等幾個方面進行闡述。(這些規範並不是一定要絕對遵守,但是一定要讓程式有良好的可讀性)


二、整體編碼風格

1、縮排

  縮排建議以4個空格為單位。建議在 Tools/Editor Options 中設定 Editor 頁面的Block nt為4,Tab Size 為8。預處理語句、全域性資料、標題、附加說明、函式說明、標號等均頂格書寫。語句塊的"{"、"}"配對對齊,並與其前一行對齊,語句塊類的語句縮排建議每個"{"、"}"單獨佔一行,便於匹對。JBuilder 中的預設方式是開始的"{"不是單獨一行,建議更改成上述格式(在 Project/Default Project Properties 中設定 Code Style 中選擇 Braces 為 Next line)。

2、空格

  原則上變數、類、常量資料和函式在其型別,修飾名稱之間適當空格並據情況對齊。關鍵字原則上空一格,如:if ( ... ) 等。運算子的空格規定如下:"::"、"->"、"["、"]"、"++"、"--"、"~"、"!"、"+"、"-"(指正負號)、"&"(引用)等幾個運算子兩邊不加空格(其中單目運算子係指與運算元相連的一邊),其它運算子(包括大多數二目運算子和三目運算子"?:"兩邊均加一空格,在作函式定義時還可據情況多空或不空格來對齊,但在函式實現時可以不用。","運算子只在其後空一格,需對齊時也可不空或多空格。不論是否有括號,對語句行後加的註釋應用適當空格與語句隔開並儘可能對齊。個人認為此項可以依照個人習慣決定遵循與否。

3、對齊

  原則上關係密切的行應對齊,對齊包括型別、修飾、名稱、引數等各部分對齊。另每一行的長度不應超過螢幕太多,必要時適當換行,換行時儘可能在","處或運算子處,換行後最好以運算子打頭,並且以下各行均以該語句首行縮排,但該語句仍以首行的縮排為準,即如其下一行為“{”應與首行對齊。

  變數定義最好透過新增空格形成對齊,同一型別的變數最好放在一起。如下例所示:
int  Value;
int  Result;
int  Length;
  currentEntry;

 個人認為此項可以依照個人習慣決定遵循與否。

4、空行

 不得存在無規則的空行,比如說連續十個空行。程式檔案結構各部分之間空兩行,若不必要也可只空一行,各函式實現之間一般空兩行,由於每個函式還要有函式說明註釋,故通常只需空一行或不空,但對於沒有函式說明的情況至少應再空一行。對自己寫的函式,建議也加上“//------”做分隔。函式內部資料與程式碼之間應空至少一行,程式碼中適當處應以空行空開,建議在程式碼中出現變數宣告時,在其前空一行。類中四個“p”之間至少空一行,在其中的資料與函式之間也應空行。

5、註釋

 註釋是軟體可讀性的具體體現。程式註釋量一般佔程式編碼量的20%,軟體工程要求不少於20%。程式註釋不能用抽象的語言,類似於"處理"、"迴圈"這樣的抽象語言,要精確表達出程式的處理說明。例如:"計算淨需求"、"計算第一道工序的加工工時"等。避免每行程式都使用註釋,可以在一段程式的前面加一段註釋,具有明確的處理邏輯。

 註釋必不可少,但也不應過多,不要被動的為寫註釋而寫註釋。以下是四種必要的註釋:
 
A. 標題、附加說明。

B. 函式、類等的說明。對幾乎每個函式都應有適當的說明,通常加在函式實現之前,在沒有函式實現部分的情況下則加在函式原型前,其內容主要是函式的功能、目的、演算法等說明,引數說明、返回值說明等,必要時還要有一些如特別的軟要求等說明。公用函式、公用類的宣告必須由註解說明其使用方法和設計思路,當然選擇恰當的命名格式能夠幫助你把事情解釋得更清楚。

C. 在程式碼不明晰或不可移植處必須有一定的說明。

D. 及少量的其它註釋,如自定義變數的註釋、程式碼書寫時間等。

 註釋有塊註釋和行註釋兩種,分別是指:"/**/"和"//"建議對A用塊註釋,D用行註釋,B、C則視情況而定,但應統一,至少在一個單元中B類註釋形式應統一。具體對不同檔案、結構的註釋會在後面詳細說明。

6、程式碼長度

 對於每一個函式建議儘可能控制其程式碼長度為53行左右,超過53行的程式碼要重新考慮將其拆分為兩個或兩個以上的函式。函式拆分規則應該一不破壞原有演算法為基礎,同時拆分出來的部分應該是可以重複利用的。對於在多個模組或者窗體中都要用到的重複性程式碼,完全可以將起獨立成為一個具備公用性質的函式,放置於一個公用模組中。

7、頁寬

 頁寬應該設定為80字元。一般不會超過這個寬度, 並導致無法完整顯示, 但這一設定也可以靈活調整. 在任何情況下, 超長的語句應該在一個逗號或者一個運算子後折行. 一條語句折行後, 應該比原來的語句再縮排2個字元.

8、行數

 一般的整合程式設計環境下,每屏大概只能顯示不超過50行的程式,所以這個函式大概要5-6屏顯示,在某些環境下要8屏左右才能顯示完。這樣一來,無論是讀程式還是修改程式,都會有困難。因此建議把完成比較獨立功能的程式塊抽出,單獨成為一個函式。把完成相同或相近功能的程式塊抽出,獨立為一個子函式。可以發現,越是上層的函式越簡單,就是幾個子函式,越是底層的函式完成的越是具體的工作。這是好程式的一個標誌。這樣,我們就可以在較上層函式里容易控制整個程式的邏輯,而在底層的函式里專注於某方面的功能的實現了。


三、程式碼檔案風格

所有的 Java(*.java) 檔案都必須遵守如下的樣式規則:

. 檔案生成

對於規範的 JAVA 派生類,儘量用 JBuilder 的 Object Gallery 工具來生成檔案格式,避免用手工製作的標頭檔案/實現檔案。
 
. package/import

package 行要在 import 行之前,import 中標準的包名要在本地的包名之前,而且按照字母順序排列。如果 import 行中包含了同一個包中的不同子目錄,則應該用 * 來處理。

package hotlava.stats;

import java.io.*;
import java.util.Observable;
import hotlava.util.Application; 
 
這裡 java.io.* 使用來代替InputStream and OutputStream 的。

. 檔案頭部註釋

檔案頭部註釋主要是表明該檔案的一些資訊,是程式的總體說明,可以增強程式的可讀性和可維護性。檔案頭部註釋一般位於 package/imports 語句之後,Class 描述之前。要求至少寫出檔名、建立者、建立時間和內容描述。JBuilder 的 Object Gallery 工具生成的程式碼中會在類、工程檔案中等自動新增註釋,我們也要新增一些註釋,其格式應該儘量如下:

/**
 * Title:  確定滑鼠位置類
 * Description: 確定滑鼠當前在哪個作業欄位中並返回作業號
 * @Copyright: Copyright (c) 2002
 * @Company: HIT
 * @author: rivershan
 * @version: 1.0
 * @time: 2002.10.30
 */
 
. Class

接下來的是類的註釋,一般是用來解釋類的。

/**
 * A class representing a set of packet and byte counters
 * It is observable to allow it to be watched, but only
 * reports changes when the current set is complete
 */ 
 
接下來是類定義,包含了在不同的行的 extends 和 implements

public class CounterSet
 extends Observable
 implements Cloneable

.Class Fields

接下來是類的成員變數:

/**
 * Packet counters
 */
 
protected int[] packets;
 
public 的成員變數必須生成文件(JavaDoc)。proceted、private和 package 定義的成員變數如果名字含義明確的話,可以沒有註釋。

. 存取方法
 
接下來是類變數的存取的方法。它只是簡單的用來將類的變數賦值獲取值的話,可以簡單的寫在一行上。(個人認為儘量分行寫)

/**
 * Get the counters
 * @return an array containing the statistical data.  This array has been
 * freshly allocated and can be modified by the caller.
 */
 
public int[] getPackets()
{
 return copyArray(packets, offset);
}

public int[] getBytes()
{
 return copyArray(bytes, offset);
}

public int[] getPackets()
{
 return packets;
}

public void setPackets(int[] packets)
{
 this.packets = packets;
}
 
其它的方法不要寫在一行上

. 建構函式

接下來是建構函式,它應該用遞增的方式寫(比如:引數多的寫在後面)。

訪問型別("public","private" 等.)和任何"static","final"或"synchronized"應該在一行中,並且方法和引數另寫一行,這樣可以使方法和引數更易讀。

public
CounterSet(int size)
{
   this.size = size;
}

. 克隆方法
 
如果這個類是可以被克隆的,那麼下一步就是 clone 方法:

public
Object clone()
{
 try
   {
   CounterSet obj = (CounterSet)super.clone();
   obj.packets = (int[])packets.clone();
   obj.size = size;
   return obj;
   } 
   catch(CloneNotSupportedException e)
   {
   throw new InternalError("Unexpected CloneNotSUpportedException: "
   + e.getMessage());
   }
}

. 類方法

下面開始寫類的方法:

/**
 * Set the packet counters
 * (such as when restoring from a database)
 */
protected final
void setArray(int[] r1, int[] r2, int[] r3, int[] r4)
  throws IllegalArgumentException
{
 //
   // Ensure the arrays are of equal size
   //
   if (r1.length != r2.length || r1.length != r3.length || r1.length != r4.length)
 throw new IllegalArgumentException("Arrays must be of the same size");
   System.arraycopy(r1, 0, r3, 0, r1.length);
   System.arraycopy(r2, 0, r4, 0, r1.length);
}

. toString 方法

無論如何,每一個類都應該定義 toString 方法:

public
String toString()
{
 String retval = "CounterSet: ";
  for (int i = 0; i < data.length(); i++)
  {
   retval += data.bytes.toString();
   retval += data.packets.toString();
  }
  return retval;
}

. main 方法

如果main(String[]) 方法已經定義了, 那麼它應該寫在類的底部.


四、函式編寫風格

. 函式的命名

通常,函式的命名也是以能表達函式的動作意義為原則的,一般是由動詞打頭,然後跟上表示動作的名詞,各單詞的首字母應該大寫。另外,還有一些函式命名的通用規則。如取數,則用Get打頭,然後跟上要取的物件的名字;設定數,則用Set打頭,然後跟上要設的物件的名字;而物件中為了響應訊息進行動作的函式,可以命名為On打頭,然後是相應的訊息的名稱;進行主動動作的函式,可以命名為Do打頭,然後是相應的動作名稱。類似的規則還有很多,需要程式設計師多讀優秀的程式,逐漸積累,才能作出好的函式命名。

. 函式註釋

自動生成的函式,如滑鼠動作響應函式等,不必太多的註釋和解釋;

對於自行編寫的函式,若是系統關鍵函式,則必須在函式實現部分的上方標明該函式的資訊,格式如下:

/**
* 函式名:
* 編寫者:
* 參考資料:
* 功  能:
* 輸入引數:
* 輸出引數:
* 備  注:
*/

希望儘量遵循以上格式。


五、符號風格

. 總體要求

對於各種符號的定義,都有一個共通點,就是應該使用有實際意義的英文單詞或英文單詞的縮寫,不要使用簡單但沒有意義的字串,儘可能不使用阿拉伯數字,更切忌使用中文拼音的首字母。如這樣的名稱是不提倡的:Value1,Value2,Value3,Value4 …。

例如:
file(檔案),code(編號),data(資料),pagepoint(頁面指標), faxcode(傳真號) ,address(地址),bank(開戶銀行),……

. 變數名稱

a. 變數名字首的約定

變數型別  字首  示例
integer  int  intCount
byte  byt  bytMove
short  sht  shtResult
long  lng  lngTotal
float  flt  fltAverage
double  l  dblTolerangce
boolean  bln  blnIsover
Char  chr  chrInput
Array  arr  arrData

變數名一般要有一定的表達義,變數名中的每一個單詞的第一個字母都要大寫出(除去第一個單詞外)

b. 描述性變數名和過程名:

變數名或過程名的主體使用大小寫混合格式並且儘量完整地描述其目的,另外過程名應以動詞開始如:InitNameArray ,CloseDialog

. 物件名的約定:

物件名的字首約定:

物件型別  字首
Button  btn
Canvas 
CheckBox  chk
Image  img
Label  lbl
List  lst
Choice  chc
Dialog  dlg
Event  evt
Frame  frm
Menu  menu
Panel  pnl
TextArea  txa
TextField  txf

. Package 的命名

Package 的名字應該都是由一個小寫單片語成。

. Class 的命名

Class 的名字必須由一個或數個能表達該類的意思的大寫字母開頭而其它字母都小寫的單詞或縮寫組成,這樣能使這個 Class 的名稱能更容易被理解。

. Class 變數的命名

變數的名字必須用一個小寫字母開頭。後面的單詞用大寫字母開頭。對於類的成員變數,在對其識別符號命名時,要加上代表member(成員)的字首m_。例如一個識別符號為m_dwFlag,則它表示的變數是一個型別為雙字的成員變數,它是代表一個標誌。

. Static Final 變數的命名

Static Final 變數的名字應該都大寫,並且指出完整含義。

. 引數的命名

引數的名字必須和變數的命名規範一致。

. 陣列的命名

陣列應該總是用下面的方式來命名:
byte[] buffer; 
 
而不是:
byte buffer[];

. 方法的引數
 
使用有意義的引數命名,如果可能的話,使用和要賦值的欄位一樣的名字:

SetCounter(int size)
{
 this.size = size;
}

. 神秘的數

首先要說什麼是神秘的數。我們在程式裡經常會用到一些量,它是有特定的含義的。例如,現在我們寫一個薪金統計程式,公司員工有50人,我們在程式裡就會用50這個數去進行各種各樣的運算。在這裡,50就是"神秘的數"。為什麼稱它為神秘呢?因為別的程式設計師在程式裡看到50這個數,不知道它的含義,只能靠猜了。

在程式裡出現"神秘的數"會降低程式的可讀性,應該儘量避免。避免的方法是把神秘的數定義為一個常量。注意這個常量的命名應該能表達該數的意義,並且應該全部大寫,以與對應於變數的識別符號區別開來。例如上面50這個數,我們可以定義為一個名為NUMOFEMPLOYEES的常量來代替。這樣,別的程式設計師在讀程式的時候就可以容易理解了。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-996647/,如需轉載,請註明出處,否則將追究法律責任。

相關文章