Java編程規范


Java編程規范

 

版本信息

 

* A代表新增,M代表修改,D代表刪除。

版本號

發布日期

提交人

審閱人

A.M.D

更新位置

更新摘要

 

 

 

 

 

 

 

 

 

 

 


目錄

1       概述.... 5

1.1      目標:.... 5

1.2      原則:.... 5

2       Java編程命名規范.... 5

2.1      包的命名標准.... 6

2.1.1命名包.... 6

2.2      類、接口的命名標准.... 6

2.2.1         命名類.... 6

2.2.2         命名接口.... 6

2.2.3         命名編譯單元.... 6

2.3      成員函數命名標准.... 7

2.3.1         命名成員函數.... 7

2.3.2         獲取函數.... 7

2.3.3         設置函數.... 7

2.3.4         命名構造函數.... 8

2.3.5         成員函數的可見性.... 8

2.4      字段/屬性 命名標准.... 9

2.4.1         命名字段.... 9

2.4.2         命名組件(部件).... 9

2.5      局部變量命名標准.... 9

2.5.1         命名流.... 9

2.5.2         命名循環計數器.... 10

2.5.3         命名異常對象.... 10

2.6      成員函數參數命名標准.... 10

3      Java編程注釋規范.... 10

3.1      注釋約定:.... 10

3.1.1         Java 注釋語句類型.... 10

3.1.2         javadoc標志.... 11

3.2      包的注釋標准.... 12

3.3      類、接口的注釋標准.... 12

3.3.1         注釋類.... 12

3.3.2         注釋接口.... 13

4      成員函數注釋標准.... 13

4.1      成員函數的函數頭.... 13

4.1.1         內部注釋.... 14

4.2      字段/屬性 注釋標准.... 16

4.2.1         注釋一個字段.... 16

4.3      局部變量注釋標准.... 16

4.3.1         聲明和注釋局部變量.... 16

4.4      成員函數參數注釋標准.... 16

5      Java編程格式規范.... 17

5.1      if-else-elseif. 17

5.2      switch. 17

5.3      while. 17

5.4      do … while. 18

5.5      for. 18

5.6      try-catch. 18

6       Java錯誤和異常處理規范.... 18

6.1      Java程序錯誤和異常處理原則.... 18

6.2      在底層的類中.... 18

6.3      在高層的類中.... 19

7      Java編程一般約定:.... 20

7.1      將公共和保護接口最小化.... 20

7.2      編程一般約定.... 20

8      其他.... 21

8.1      編寫清晰整潔的代碼的原則.... 21

8.1.1         給代碼加上注釋.... 22

8.1.2         讓代碼分段/縮進.... 22

8.1.3         遵循 30 秒條法則.... 22

8.1.4         寫短小單獨的命令行.... 22

8.1.5         說明運行順序.... 22

8.2      為什么采用存取函數?.... 22

 


 

 

1      概述

1.1 目標:

建立一個可行可操作的編程標准、約定和指南,以規范我們的代碼開發工作。提高代碼的可讀性,提高系統的健壯性、穩定性、可靠性。通過遵循這些程序設計標准,作為一個 Java 軟件開發者的生產效率會有顯著提高。經驗證明,若從一開始就花時間編寫高質量的代碼,則在軟件開發階段,對代碼的修改要容易很多。最后,遵循一套通用的程序設計標准將帶來更大的一致性,使軟件開發團隊的效率明顯提高。

1.2 原則:

運用常識

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

當你要違反一個標准時,注釋你的原因

當你要違反一個標准時,你這樣做的時候,你必須注釋你違反這個標准的原因,違反標准的潛在原因以及在何種條件(可能/必須)滿足的情況下,標准可以被應用到這個情況中。

代碼的可維護性

你的 Java 代碼在你已離開並開始另一個項目之后,會保留相當長的一段時間。因此開發過程中一個很重要的目標就是要確保在開發成員或開發團隊之間的工作可以順利交接,不必花很大的力氣便能理解已編寫的代碼,以便繼續維護和改進以前的工作。

 

2      Java編程命名規范

一般約定:

命名時應始終采用完整的英文描述符。此外,一般應采用小寫字母,但類名、接口名以及任何非初始單詞的第一個字母要大寫。

  1. 使用可以准確說明變量/字段/類的完整的英文描述符。例如,采用類似 firstNamegrandTotalCorporateCustomer 這樣的名字。雖然象 x1y1fn 這樣的名字很簡短,輸入起來容易,但是我們難以知道它們代表什么、結果是什么含義,因而使代碼以理解、維護和改進。
  2. 采用該領域的術語。如果用戶稱他們的“客戶” (clients) 為“顧客” mers),那么就采用術語 Customer 來命名這個類,而不用 Client。許多程序開發者會犯的一個錯誤是,不去使用工業或領域里已經存在着很完美的術語時,卻生造出一些普通詞匯。
  3. 采用大小寫混合,提高名字的可讀性。一般應該采用小寫字母,但是類和接口的名字的首字母,以及任何中間單詞的首字母應該大寫。
  4. 盡量少用縮寫,但如果需要使用,可以選擇單詞的頭4個字母作為縮寫。如:DeptInfoValue,MapActi, MapActiInst 等等。
  5. 避免使用長名字(最好不超過 15 個字母)。 雖然 PhysicalOrVirtualProductOrService 看起來似乎是個不錯的類名,但是這個名字太長了,應該考慮重新給它起個短一點的名字,比如象 Offering
  6. 避免使用相似或者僅在大小寫上有區別的名字。例如,不應同時使用變量名 persistentObjectpersistentObjects,以及 anSqlDatabaseanSQLDatabase
  7. 避免使用下划線作為名字的首末字母。以下划線為首末字母的名字通常為系統保留,除預處理定義之外,一般不用作用戶命名。更重要的是,下划線經常造成麻煩而且難輸入,所以盡量避免使用。

2.1 包的命名標准

2.1.1命名包

關於包的命名有幾條規則,這些規則是:

1、 包的命名都是使用小寫的英文字母組成,每個包名稱之間用點號分隔開來。如java.lang;javax.servlet.http 等。

2、 全局包的名字用所在機構的 Internet 保留域名開頭。如:com.sun   com.oracle. 等等

3、 我們的命名約定:

com.excellence.common  excellence下的通用文件,可能被以后不同項目通用的類文件。

com.excellence.exoa4j exoa2004forjava項目的java分模塊分類存放。

在com.excellence.exoa4j下面,我們在按照模塊,分開各自的包。

 

2.2 類、接口的命名標准

2.2.1命名類

標准 Java類約定是使用完全的英文描述符,所有單詞的第一個字母要大寫,並且單詞中大小寫混合。

類名應是單數形式。

示例:

Customer   Employee        Order    OrderItem        FileStream        String

     相關的類如果使用了某些已經約定的開發模式,應該使用相關約定的命名:如:LoggerFactory , UserDAO 等。

     在同一個模塊中的相關類,可以采用同樣開頭的名稱以區分他們的相關性。如:UserValue, UserDAO 等。

2.2.2命名接口

采用完整的英文描述符說明接口封裝,所有單詞的第一個字母大寫。習慣上,名字后面加上后綴 able,. ible 或者 er。

示例:

Runnable, Contactable,

Prompter, Singleton

2.2.3命名編譯單元

編譯單元,在這個情況下是一個源碼文件,應被賦予文件內定義的主要的類或接口的名字。用與包或類相同的名字命名文件,大小寫也應相同。擴展名 .java 應作為文件名的后綴。

示例:

Customer.java

Singleton.java

DeptInfo.java

 

2.3 成員函數命名標准

2.3.1命名成員函數

成員函數的命名應采用完整的英文描述符,大小寫混合使用:所有中間單詞的第一個字母大寫。成員函數名稱的第一個單詞常常采用一個有強烈動作色彩的動詞。

示例:

openAccount()   printMailingLabel() createUser()   delete()

這種約定常常使人一看到成員函數的名稱就能判斷它的功能。雖然這種約定要使開發者多做一些輸入的工作,因為函數名常常較長,但是回報是提高代碼的可理解性。

2.3.2獲取函數

獲取函數作為一個成員函數,返回一個字段的值。除了布爾字段之外,應采用 get 作為字段的前綴;布爾字段采用 is 作為前綴。

示例:

public String getUserCode() {

    return userCode;

  }

  public String getUserName() {

    return userName;

  }

  getFirstName()

getAccountNumber()

isPersistent()

isAtEnd()

遵循這個命名約定,顯然,成員函數將返回對象的字段,布爾型的獲取函數將返回布爾值“真”或者“假”。這個標准的另一個優點是:它遵循 beans development kit (BDK) 對獲取成員函數采用的命名約定 [DES97]。它的一個主要的缺點是 get 是多余的,需要額外的錄入工作。

按照jbuilder中bean/properties工具生成的設置和獲取函數。

2.3.3設置函數

設置函數,也叫變值函數,是可以修改一個字段值的成員函數。無論何種字段類型,都要在字段名的前面加上 set 前綴。

示例:

public void setUserCode(String userCode) {

    this.userCode = userCode;

}

public void setUserName(String userName) {

    this.userName = userName;

  }

setFirstName(String name)

setAccountNumber(int accountNumber)

setReasonableGoals(Vector goals)

setPersistent(boolean isPersistent)

setAtEnd(boolean isAtEnd)

 

按照這種命名約定,顯然是一個成員函數設定一個對象的字段值。這個標准的另一個優點是:它遵循 beans development kit (BDK) 對設置函數采用的命名約定 [DES97]。 它的一個主要的缺點是 set 是多余的,需要額外的錄入。

按照jbuilder中bean/properties工具生成的設置和獲取函數。

2.3.4命名構造函數

構造函數是在一個對象初次生成時,完成所有必需的初始化的成員函數。構造函數與它所屬類的名字總是相同的。例如,類 Customer 的構造函數是 Customer()。注意大小寫一致。

示例:

Customer()

SavingsAccount()

PersistenceBroker()

這個命名約定由 Sun 公司設定,必須嚴格遵守。

2.3.5成員函數的可見性

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

可見性

Java關鍵字

說明

正確用法

公共

public

公有成員函數可被任何其它對象和類的成員函數調用。

當該成員函數必須被該函數所在的層次結構之外的其他對象和類在訪問時。

受保護

protected

被保護的成員函數可被它所在的類或該類的子類的任何成員函數調用。

當該成員函數提供的行為被它所在類的層次結構內部而非外部需要時。

專用

private

私有成員函數只可以被該類所在的其它成員函數調用,該類的子類不可以調用。

當該成員函數所提供的行為明確針對定義它的類時。私有成員函數常常是重新分配要素的結果。重新分配要素又叫“重組”,指類內其它成員函數封裝某一個特定行為的做法。

缺省

無關鍵字,簡單地使其為空白

成員函數對於同一包中的其它所有類實際上都是公共的,但是對該包外部的類是專用的。 有時,它稱為包可見性或友好的可見性。

這是一個有趣的功能,但要小心使用。 一般不建議使用。

 

 

 

 

2.4 字段/屬性 命名標准

field 這個詞在這里指的是字段,Beans Development Kit (BDK) 叫它“屬性” [DES97]。字段是說明一個對象或者一個類的一段數據。字段可以是象字符串或者浮點數這樣的基本數據類型,也可以是一個對象,例如一個消費者或者一個銀行帳戶。

2.4.1命名字段

應采用完整的英文描述符來命名字段 [GOS96],[AMB98],以便使字段所表達的意思一目了然。象數組或者矢量這樣是集合的字段,命名時應使用復數來表示它們代表多值。

示例:

firstName   zipCode unitPrice  discountRate    orderItems(復數)

2.4.2命名組件(部件)

應采用完整的英文描述符命名組件(接口部件),名字的后綴是組件類型名。這讓你容易區分一個組件的目的和它的類型,容易在一個表里找到各個組件(許多可視化的編程環境在一個 Applet 程序或者一個應用程序中提供了一個所有組件的列表。如果所有名字都是類似於 button1, button2, & 這樣的話,很容易混淆)。

示例:

okButton        customerList        fileMenu        newFileMenuItem

 

2.5 局部變量命名標准

一般說來,命名局部變量遵循與命名字段一樣的約定,即使用完整的英文描述符,任何非開頭的單詞的第一個字母要大寫。

 

 

但是為方便起見,對於如下幾個特殊的局部變量類型,這個約定可以放寬:

  • 循環計數器
  • 異常

2.5.1命名流

當有一個單輸入和/或單輸出流在一個成員函數中被打開、使用和關閉時,通常的約定是對這些流分別采用 in 和 out [GOS96] 來命名。對於既用於輸入又用於輸出的流,采用 inOut 來命名。

一個常用的取代這種約定的方法是分別采用 inputStream,outputStream 和 ioStream 這樣的名字,而不是 in,out 和 inOut,雖然這與 Sun 公司的建議相抵觸。

2.5.2命名循環計數器

因為局部變量常用作循環計數器,並且它為 C/C++ 所接受,所以在 Java 編程中,可以采用 i, j 或 k 作為循環計數器 [GOS96]。 若采用這些名字作為循環計數器,要始終使用它們。

概括起來說,i,j,k 作為計數器時, 它們可以很快被輸入,它們被廣泛的接受。

2.5.3命名異常對象

因為在 Java 代碼中異常處理也非常普遍,所以字母 e 作為一般的異常符被廣泛地接受。

如果有多個異常同時出現,應該使用該類型異常全稱的縮寫表示。

catch(SQLException sqlexception)

 

2.6 成員函數參數命名標准

命名參數

參數命名遵循與局部變量命名完全一樣的約定。對於局部變量,名字隱藏是一個問題。

示例:

customer        inventoryItem       photonTorpedo       in      e

一個可行的取代方法,是采用局部變量的命名約定,但在名字之前加入“a”或“an”。加上“a”或“an”有助於讓參數與局部變量和字段區分開來,避免名字隱藏的問題。這種方法較好。

示例:

aCustomer   anInventoryItem     aPhotonTorpedo  anInputStream       anException

但是,如果是設置/獲取函數,由於采用了jbuilder 下的bean/properties工具生成了代碼,可以不采用這種命名方法。而采用,this關鍵字將局部變量和函數參數區分開。

如:public void setUserName(String userName) {

    this.userName = userName;

  }

3   Java編程注釋規范

3.1 注釋約定:

3.1.1Java 注釋語句類型

Java 有三種注釋語句風格:

以 /** 開始, */ 結束的文檔注釋,

以 /* 開始,以 */ 結束的C語言風格注釋,

以及以 // 開始,代碼行末尾結束的單行注釋。

下表是對各類注釋語句建議用法的一個概括,也給出了幾個例子。

注釋語句類型

用法

示例

文檔注釋

在接口、類、成員函數和字段聲明之前緊靠它們的位置用文檔注釋進行說明。文檔注釋由 javadoc 處理,為一個類生成外部注釋文檔,如下所示。

/**

Customer (顧客).顧客是指作為我們的服務及產品的銷售對象的任何個人或組織。

@author S.W. Ambler

*/

C語言風格注釋

采用 C 語言風格的注釋語句將無用的代碼注釋掉。保留這些代碼是因為用戶可能改變想法,或者只是想在調試中暫時不執行這些代碼。

/*

這部分代碼已被它前面的代碼替代,所以於 1999 年6 月 4 日被 B. Gustafsson 注釋掉。如果兩年之后仍未用這些代碼,將其刪除。

. . . (源代碼)

*/

單行注釋

在成員函數內部采用單行注釋語句對業務邏輯、代碼片段和臨時變量聲明進行說明。

// 因為讓利活動

// 從 1995 年 2 月開始,

// 所以給所有超過 $1000 的

// 發貨單 5% 的折扣。

 

使用單行注釋方式來說明業務邏輯,使用C 語言風格的注釋屏蔽舊的代碼。

業務邏輯采用單行注釋,因為這樣可以將注釋和代碼放在同一行(這又叫做“內聯”)。采用 C 語言風格的注釋屏蔽掉舊的代碼,因為這樣可以同時注釋掉數行。C 語言風格注釋看起來很象文檔注釋,所以為了防止混淆,不應在別處使用。

3.1.2javadoc標志

Sun 公司的 Java Development Kit (JDK) 中有一個名為 javadoc 的程序。它可以處理 Java 的源代碼文件,並且為 Java 程序產生 HTML 文件形式的外部注釋文檔。Javadoc 支持一定數目的標記,標識注釋文檔中各段起始位置的保留字。詳情請參考 JDK javadoc 文檔。

標記

用於

目的

@author name

類、

接口

說明特定某一段程序代碼的作者。每一個作者各有一個標記。

@deprecated

類、

成員函數

說明該類的應用程序編程接口 (API) 已被廢棄,因此應不再使用。

@exception name description

成員函數

說明由成員函數發出的異常。一個異常采用一個標記,並要給出異常的完整類名。

@param name description

成員函數

用來說明傳遞給一個成員函數的參數,其中包括參數的類型/類和用法。每個參數各有一個標記。

@return description

成員函數

若成員函數有返回值,對該返回值進行說明。應說明返回值的類型/類和可能的用途。

@since

類、成員函數

說明自從有 JDK 1.1 以來,該項已存在了多長時間。

@see ClassName

類、接口、成員函數、字段

在文檔中生成指向特定類的超文本鏈接。可以並且應該采用完全合法的類名。

@see ClassName#member functionName

類、接口、成員函數、字段

在文檔中生成指向特定成員函數的超文本鏈接。可以並且應該采用完全合法的類名。

@version text

類、接口

說明特定一段代碼的版本信息。

你注釋代碼的方式很大地影響着你的工作效率以及所有維護改進代碼的后繼開發者的工作效率。在軟件開發過程中及早注釋代碼,會促使你在開始撰寫代碼之前仔細考慮這些代碼,從而帶來更高的工作效率。而且,當你重新閱讀數天前或者數星期前所寫的代碼時,你可以很容易地判斷出當時你是怎么想的,因為這一切都有記錄。

 

3.2 包的注釋標准

注釋包

應保有一個或者多個外部文檔以說明你的機構所創建的包的用途。對於每個包,應說明:

  1. 包的基本原理。其他開發者需要了解一個包是用來做什么的,這樣他們才能判斷是否可以用它,如果是一個共享包,他們可以判斷是否需要改進或是擴展它。
  2. 包中的類。在包中要包含一個類和接口的列表,每個類或接口用簡短的一行文字來說明,以便讓其他的開發者了解這個包中含有什么。

技巧:生成一個以包名命名的 HTML 文件,將它放到包的適當的目錄中去。這個文件應具有后綴 .htm

 

 

3.3 類、接口的注釋標准

3.3.1注釋類

以下的信息應寫在文檔注釋中緊靠類的定義的前面:

  1. 類的目的和作用。開發者需要了解一個類的一般目的,以判斷這個類是否滿足他們的需求。養成一個注釋與類有關的任何好東西的習慣。
  2. 已知的問題。如果一個類有任何突出的問題,應說明出來,讓其他的開發者了解這個類的缺點/難點。此外,還應注明為什么不解決問題的原因。
  3. 類的開發/維護歷史。通常要包含一個歷史記錄表,列出日期、類的作者和修改概要。這樣做的目的是讓進行維護的程序員了解過去曾對一個類所做的修改,是誰做了什么樣的修改。
  4. 版權信息。

對於以上幾點:其中類的目的和作用這項是必須要填寫的。采用Javadoc形式標志的一個示例如下:

/**

 * <p>類說明: LoggerFactory,創建Logger的工廠類</p>

 * <p>Copyright 2003: Excellence Network Co.,LTD</p>

 * @author fjy

 * @version 1.0

 * @since 2003-06-10

 * @modified fjy 2003-06-13  修改了XXXX

* @modified fjy 2003-06-23  修改了XXXX

 */

3.3.2注釋接口

以下的信息應寫在文檔注釋中緊靠接口定義的前面:

  1. 目的。在其他開發者應用一個接口之前,他們需要理解接口封裝的概念。換句話說,他們需要了解接口的目的。一個好的檢測是否有必要定義一個接口的方法是你是否可以很容易地說明它的目的。 如果說明起來有困難,很可能從一開始起就不需要這個接口。在 Java 中接口的概念較新,所以人們對如何正確使用它們還不是很有經驗,常常濫用它們。
  2. 它應如何被使用以及如何不被使用。開發者需要了解接口應如何使用以及如何不被使用。

因為成員函數的標識在接口中定義,所以對於每個成員函數的標識應遵循第二章中所討論的注釋約定。

 

示例如下:

/**

 * <p>接口說明: Runnable,作為線程的接口。實現run()方法,可以實現線程的效果。</p>

 * <p>Copyright 2003: Excellence Network Co.,LTD</p>

 * @author fjy

 * @version 1.0

 * @since 2003-06-10

 * @modified fjy 2003-06-13  修改了XXXX

*/

 

4   成員函數注釋標准

注釋一個成員函數是為了函數更加可被理解,進而可維護和可擴展。

4.1 成員函數的函數頭

每一個 Java 成員函數都應包含某種稱之為“成員函數文檔”的函數頭。這些函數頭在源代碼的前面,用來記錄所有重要的有助於理解函數的信息。 這些信息包含但不僅僅局限於以下內容:

  1. 成員函數做什么以及它為什么做這個。通過給一個成員函數加注釋,讓別人更加容易判斷他們是否可以復用代碼。注釋出函數為什么做這個可以讓其他人更容易將你的代碼放到程序的上下文中去。也使其他人更容易判斷是否應該對你的某一段代碼加以修改(有可能他要做的修改與你最初為什么要寫這一段代碼是相互沖突的)。
  2. 哪些參數必須傳遞給一個成員函數。還必須說明,如果帶參數,那么什么樣的參數必須傳給成員函數,以及成員函數將怎樣使用它們。這個信息使其他程序員了解應將怎樣的信息傳遞給一個成員函數。javadoc @param 標識便用於該目的。
  3. 成員函數返回什么。如果成員函數有返回值,則應注釋出來,這樣可以使其他程序員正確地使用返回值/對象。javadoc @return 標識便用於此目的。
  4. 已知的問題。成員函數中的任何突出的問題都應說明,以便讓其他程序開發者了解該成員函數的弱點和難點。如果在一個類的多個成員函數中都存在着同樣的問題,那么這個問題應該寫在類的說明里。
  5. 任何由某個成員函數拋出的異常。應說明成員函數拋出的所有異常,以便使其他程序員明白他們的代碼應該捕獲些什么。javadoc @exception 標識便用於此目的。
  6. 如何在適當情況下調用成員函數的例子。最簡單的確定一段代碼如何工作的方法是看一個例子。考慮包含一到兩個如何調用成員函數的例子。
  7. 可用的前提條件和后置條件。 前提條件是指一個成員函數可正確運行的限制條件;后置條件是指一個成員函數執行完以后的屬性或聲明 [MEY88]。前提條件和后置條件以多種方式說明了在編寫成員函數過程中所做的假設 [AMB98],精確定義了一個成員函數的應用范圍。
  8. 成員函數的開發/維護歷史。通常要包含一個歷史記錄表,列出日期、修改的作者和修改概要。這樣做的目的是讓進行維護的程序員了解過去曾對一個成員函數所做的修改,是誰做了什么樣的修改。

示例:

/**

   * 執行SELECT函數,可以分頁。按照輸入的頁碼、每頁的行數,返回當前頁的結果集

   * 又多行記錄:結果放入VECTOR,VECTOR里面的每一項代表一行記錄。

   *          VECTOR里面包含的String[]就是真正的結果

   * @param pageNo 返回SELECT結果中的第幾頁數據

   * @param pageCount 每頁的最大行數

   * @throws java.lang.Exception

   *  modified by fjy 2003-07-03 增加了pageCount參數的檢查

   */

public void ExecuteSelect(int pageNo,int pageCount)  throws Exception  {

 

}

4.1.1內部注釋

除成員函數注釋以外,在成員函數內部還需加上注釋語句來說明你的工作。 目的是使成員函數更易理解、維護和增強。

內部注釋應采用兩種方式:C 語言風格的注釋 (/* 和 */) 和單行注釋 (//)。正如上述所討論的,應認真考慮給代碼的業務邏輯采用一種風格的注釋,給要注釋掉的無用代碼采用另外一種風格的注釋。對業務邏輯采用單行注釋,因為它可用於整行注釋和行末注釋。采用 C 語言風格的注釋語句去掉無用的代碼,因為這樣僅用一個語句就可以容易地去掉幾行代碼。此外,因為 C 語言風格的注釋語句很象文檔注釋符。它們之間的用法易混淆,這樣會使代碼的可理解性降低。所以,應盡量減少使用它們。

在函數內,需要注釋說明的地方:

  1. 控制結構。說明每個控制結構,例如比較語句和循環。你無須讀完整個控制結構內的代碼才判斷它的功能,而僅需看看緊靠它之前的一到兩行注釋即可。
  2. 代碼做了些什么以及為什么這樣做。通常你常能看懂一段代碼做了什么,但對於那些不明顯的代碼,你很少能判斷出它為什么要那樣做。例如,看完一行代碼,你很容易地就可以斷定它是在定單總額上打了 5% 的折扣。這很容易。不容易的是為什么要打這個折扣。顯然,肯定有一條商業法則說應打折扣,那么在代碼中至少應該提到那條商業法則,這樣才能使其他開發者理解你的代碼為什么會是這樣。
  3. 局部變量。雖然我們在第 4 章將仔細討論這一點,在一個成員函數內定義的每一個局部變量都應在它代碼的所在行聲明,並且應采用一個行內注釋說明它的用法。
  4. 難或復雜的代碼。若發現不能或者沒有時間重寫代碼,那么應將成員函數中的復雜代碼詳細地注釋出來。一般性的經驗法則是,如果代碼並非顯而易見的,則應說明。
  5. 處理順序。如果代碼中有的語句必須在一個特定的順序下執行,則應保證將這一點注釋出來 [AMB98]。沒有比下面更糟糕的事了:你對一段代碼做一點簡單的改動,卻發現它不工作,於是花了幾個小時查找問題,最后發現原來是搞錯了代碼的執行順序。

在閉括號后加上注釋。常常會發現你的控制結構內套了一個控制結構,而在這個控制結構內還套了一個控制結構。雖然應該盡量避免寫出這樣的代碼,但有時你發現最好還是要這樣寫。問題是閉括號 } 應該屬於哪一個控制結構這一點就變得混淆了。一個好消息是,有一些編輯器支持一種特性:當選用了一個開括號后,它會自動地使相應得閉括號高亮顯示;一個壞消息是,並非所有的編輯器都支持這種屬性。我發現通過將類似 //end if//end for//end switch,&這樣的注釋加在閉括號所在行的行后,可以使代碼更易理解。

實例:

注釋一段代碼的作用

//sql語句是否為空

    if(strSQL == null){

        throw(new Exception ("查詢語句為空!"));

    }

 

注釋一段不使用的代碼

/*以下代碼已經暫停使用  by fjy 2003-07-02

for (int i = 0, l = ve.size(); i < l; i++) {

      String[] sre = (String[]) (ve.elementAt(i));

      user = new User();

      user.setUserCode(sre[0]);

      user.setUserName(sre[1]);

      user.setDeptCode(sre[2]);

      user.setUserTitle(sre[3]);

      user.setUserOffi(sre[4]);

      user.setUserPhone(sre[5]);

      user.setUserAddr(sre[6]);

      alist.add(user);

}

*/

4.2 字段/屬性 注釋標准

4.2.1注釋一個字段

字段都應很好地加以注釋,以便其他開發者理解它。要想有效地注釋,以下的部分需要說明:

  1. 字段的說明。需說明一個字段,才能使人了解如何使用它。
  2. 注釋出所有采用的不變量。字段中的不變量是指永遠為“真”的條件。例如,字段 dayOfMonth 的不變量可能是它的值只能在 1 到 31 之間(顯然,可以用基於某一年里的某個月份來限制這個字段值,使其變的更加復雜)。通過說明字段值的限制條件,有助於定義重要的業務規則,使代碼更易理解。

  示例:

 

//最終執行的SQL 語句

  protected String     strSQL = null;

  //需要連接數據源的名稱

  private   String     dsName;

 

4.3 局部變量注釋標准

4.3.1聲明和注釋局部變量

在 Java 中聲明和注釋局部變量有幾種約定。這些約定是:

  1. 一行代碼只聲明一個局部變量。這與一行代碼應只有一個語句相一致,並使得對每個變量采用一個行內注釋成為可能。
  2. 用一個行內注釋語句說明局部變量。行內注釋是一種緊接在同一行的命令代碼后,用符號 // 標注出來的單行注釋風格(它也叫“行末注釋”)。應注釋出一個局部變量用於做什么、在哪里適用、為什么要用等等,使代碼易讀。

如:

int count = 1;  //記錄循環次數

int pangeSize = 5;  //頁面的大小

4.4 成員函數參數注釋標准

注釋參數

成員函數的參數在采用 javadoc @param 標識的頭文件中注釋。應說明:

  1. 參數用來做什么。需要注釋出參數用來做什么,以便其他開發者了解使用參數的上下文。
  2. 任何約束或 前提條件。 如果一個參數的值域不能被成員函數接收,則應讓調用者知道。可能一個成員函數只接收正數,或者字符數小於五的字符串。
  3. 示例。如果應傳遞什么樣的參數不明顯,那么應該在注釋中給出一個或多個例子。

 

5   Java編程格式規范

         為了對應jbuilder工具的一些默認設置,我們定義大括號“{”一般放在一行語句的結尾。常見的格式示例如下:

5.1 if-else-elseif

如果是if…elseif…else的情況,超過一行的執行體語句要分行,如果其中有任何一個的執行體使用了花括號,就應該都使用花括號。

 

if ( a > b )

                   a = a + 1 ;

         else

                   a = a - 1 ;

 

         if ( ( a > b ) && ( a > c ) ){

                   b = b - 1 ;

                   c = c - 1 ;

         }else if ( a > b ){

                   b = b - 1 ;

         }else if ( a > c ){

                   c = c - 1 ;

         }else{

                   a = a + 1 ;

         }

5.2 switch

Switch語句應該都帶有一個default,當出現了意料之外的情況時可以在default中拋出異常。

switch(n)  

{        

          case 0:  

                   do3();

      break;

          case 1:  

                   do1();

                   break;

          case 2: 

                   do2();

                   break;

          case 3:

                   do3();

                   break;

          default:

                   dodefault();

                   break;

}

5.3  while

while語句也是循環性質,所以也要使用花括號

while (n < 6) {

         System.out.println("Current value of n is {0}", n);

         n++;

}

5.4 do … while

do語句因為使用的情況較少,最好是盡量使用while來代替do

do{

         System.out.println("Current value of n is {0}", n);

         n++;

}while (n < 6)

 

5.5 for

for語句因為具有循環的性質,應該使用花括號明確的標出語句塊的范圍

for (int i = 0; i < aa.length; i++) {

    System.out.println(aa[i]);

}

 

5.6 try-catch

try-catch是異常捕捉的語句,做為語言本身的規定,就必須使用花括號。

try {

 

}catch (Exception ex) {

          ex.printStackTrace();

}catch (ClassNotFoundException classnotfoundexception) {

          classnotfoundexception.printStackTrace();

}finally {

    Logger.log("ddd");

}

 

6     Java錯誤和異常處理規范

6.1 Java程序錯誤和異常處理原則

為了系統的穩定性,應該保證代碼的健壯性。時時刻刻檢查是否有異常產生,並按以下的原則處理。在底層的類中,如果沒有顯示的界面,應該在相關的log日志文件中記錄錯誤;如果在有顯示界面的層中,應該在記錄log日志文件的同時,顯示相關的出錯信息。

在成員函數中應該檢查參數的合法性,運行狀態中參數的合法性,執行結果是否為null等。

不同模塊可以定義自己的異常類,按照實際運行過程可能出現的

6.2 在底層的類中

在底層的類中出現的異常可以在log的同時,再往外拋出異常。如:

 

/**

   * 通過數據源名稱取數據源

   * @param dataSourceName

   * @return

   * @throws java.lang.Exception

   */

 public static Connection getConnection(String dataSourceName) throws Exception

 {

 

          DataSource ds = null;

          try{

                    //先取服務器的命名空間,再通過數據源的jndi名稱取得數據源

                    Context initCtx = new InitialContext();

                    Context envCtx = (Context) initCtx.lookup("java:comp/env");

                    ds = (DataSource)envCtx.lookup(dataSourceName);

          } catch (Exception e) {

                      //使用log

                      LoggerFactory.getInstance().error("Error looking up the DataSource object: " + e);

                      //在底層先不處理異常

                      throw e;

          }

          return ds.getConnection();

 

  }

 

 

6.3 在高層的類中

在高層的類中,在頁面中出現的異常,則應該引導到出錯頁面,並顯示相關的錯誤信息。

Jsp中的處理:

LogWriterDemo<br>

<%

 

try{

//LogWriter

    LogWriter.logInfo("modue","source","working","user1",request,"memory");

}catch(Exception ee){

response.sendRedirect(/error.jsp);

}

 

%>

 

 

servlet中的處理:

try{

               performTask(request,response);

            }

            catch (Exception e){

                    //使用默認的exoa4j的實例打印錯誤信息

                    LoggerFactory.getInstance().error(this, e);

                    try{

                            request.setAttribute( "msg", e.getMessage() );

                            toNextPage( "/error.jsp", request, response );

                            return;

                    }catch ( Exception ex ){

                            //使用默認的exoa4j的實例打印錯誤信息

                            LoggerFactory.getInstance().error(this, ex);

                    }

            }

 

7   Java編程一般約定:

7.1 將公共和保護接口最小化

面向對象程序設計的基本點之一是最小化一個類的公共接口。這樣做有幾個理由:

  1. 可學習性。要了解如何使用一個類,只需了解它的公共接口即可。公共接口越小,類越容易學習。
  2. 減少耦合。當一個類的實例向另一個類的實例或者直接向這個類發送一條消息時,這兩個類變得耦合起來。最小化公共接口意味着將耦合的可能降到最低。
  3. 更大的靈活性。這直接與耦合相聯系。一旦想改變一個公共接口的成員函數的實現方法,如你可能想修改成員函數的返回值,那么你很可能不得不修改所有調用了該成員函數的代碼。公共接口越小,封裝性就越大,代碼的靈活性也越大。

盡力使公共接口最小化這一點明顯地很值得你的努力,但通常不明顯的是也應使被保護接口最小化。基本思想是,從一個子類的角度來看,它所有超類的被保護接口是公共的。任何在被保護接口內的成員函數可被一個子類調用。所以,出於與最小化公共接口同樣的理由,應最小化類的被保護接口。

首先定義公共接口。大多數有經驗的開發者在開始編寫類的代碼之前就先定義類的公共接口。 第一,如果你不知道一個類要完成怎樣的服務/行為,你仍有一些設計工作要做。第二,這樣做使這個類很快地初具雛形,以便其他有賴於該類的開發者在“真正的”類被開發出來以前至少可以用這個雛形開始工作。 第三,這種方法給你提供了一個初始框架,圍繞着這個框架你構造類。

 

7.2 編程一般約定

有許多的有關 Java 代碼可維護性和可改進性的重要約定和標准。99.9% 的時間里,面向他人,面向你的開發同事編程要比面向機器編程重要得多。使你的代碼為別人所理解是最重要的。

約定目標

約定

存取成員函數

考慮對數據庫中的字段使用滯后初始化

使用存取函數獲得和修改所有字段

對常量采用存取函數

對於集合,加入成員函數來插入和刪除項

一旦可能,將存取函數置為被保護類型,不是公共類型

字段

字段永遠為私有類型

不要直接訪問字段,應使用存取成員函數

不要使用靜態常量字段(常量),應使用存取成員函數

不要隱藏名字

一定要初始化靜態字段

最小化公共和保護接口

在開始寫代碼之前定義一個類的公共接口

按以下順序聲明一個類的字段和成員函數:

  • 構造函數
  • 公共成員函數
  • 被保護成員函數
  • 私有成員函數
  • 私有字段

局部變量

不要隱藏名字

一行代碼只聲明一個局部變量

用一個行內注釋說明局部變量

在使用局部變量之前聲明它

僅將局部變量用於一件事

成員函數

給代碼加上注釋

給代碼分段

使用空白,控制結構之前用一個空行,成員函數之前用兩個空行

一個成員函數應能在 30 秒內讓人理解

寫短小單獨的命令行

盡量限制成員函數的可見性

說明操作的順序

 

8   其他

8.1 編寫清晰整潔的代碼的原則

這一部分講述幾個技巧,這些技巧有助於區分專業軟件開發者和蹩腳代碼編寫者。這些技巧是:

  • 給代碼加上注釋
  • 給代碼分段
  • 使用空白
  • 遵循 30 秒條規則
  • 說明消息發送的順序
  • 寫短小單獨的命令行

8.1.1給代碼加上注釋

記住:如果你的代碼不值得注釋,那么它就不值得保留 [NAG95]。當正確地使用了本文提到的注釋標准和方針,就可以大幅度地提高代碼質量。

8.1.2讓代碼分段/縮進

一種提高代碼可讀性的方法是給代碼分段,換句話說,就是在代碼塊內讓代碼縮進。所有在括號 {} 之內的代碼,構成一個塊。基本思想是,塊內的代碼都應統一地縮進去一個單位。

Java 的約定似乎是開括號放在塊的所有者所在行的后面,閉括號應縮進一級。在 [LAF97] 指出的很重要的一點是,你所在的機構應選取一個縮進風格並始終使用這種風格。采用與你的 Java 開發環境所生成的代碼一樣的縮進風格。

在代碼中使用空白。在 Java 代碼中加入幾個空行,也叫空白,將代碼分為一些小的、容易理解的部分,可以使它更加可讀。[VIS96] 建議采用一個空行來分隔代碼的邏輯組,例如控制結構,采用兩個空行來分隔成員函數定義。沒有空白的代碼很難讀,很難理解。

8.1.3遵循 30 秒條法則

其他的程序員應能在少於 30 秒鍾的時間內完全理解你的成員函數,理解它做什么,為什么這樣做,它是怎樣做的。如果他們做不到,說明你的代碼太難維護,應加以改進。30 秒鍾,明明白白。 一個好的經驗法則是:如果一個成員函數一個屏幕裝不下,那么它就很可能太長了。

8.1.4寫短小單獨的命令行

每一行代碼只做一件事情。在依賴於穿孔卡片的計算機發展的早期,想讓一行代碼完成盡量多的功能的想法是可以理解的。若想在一行里做多件事情,就會使代碼難於理解。為什么要這樣呢?我們應使代碼盡量容易理解,從而更容易維護和改進。正如同一個成員函數應該並且只能做一件事一樣,一行代碼也只應做一件事情。

此外,應讓代碼在一個屏幕內可見 [VIS96]。 也不應向右滾動編輯窗口來讀取一整行代碼,包括含有行內注釋語句的代碼。

8.1.5說明運行順序

提高代碼可讀性的一個相當簡單的方法是使用圓括號 (parenthesis,又叫“round brackets”) 來說明 Java 代碼運行的准確順序 [NAG95];[AMB98]。如果為了理解你的源碼而必須了解編程語言的操作順序,那么這說明源碼中一定有什么重要的東西做的不對。 這大多是在 AND 或者 OR 其它幾個比較關系處產生的邏輯比較上的問題。注意:如果你象前文所建議的那樣,采用短小單獨的命令行,那么就不會產生這個問題。

 

8.2 為什么采用存取函數?

“好的程序設計試圖將程序部件與不必要、未計划或者不需的外部影響分隔開來。訪問修飾語句(存取函數)給編程語言控制這一類的接觸提供了一種清晰並可檢驗的方法。”

存取成員函數通過以下方法提高類的可維護性:

  1. 更新字段。.每個字段只有幾個單點要更新,這使得修改和檢測都很容易。換句話說,字段已被封裝。
  2. 獲得字段的值。你完全控制着字段應怎樣被訪問以及被誰訪問。
  3. 獲取常量名和類名。在獲取函數中封裝常量值和類名,當這些值或名字改變時,只需更新獲取函數內的值,而並非常量或者名字被使用處的每一行代碼。
  4. 初始化字段。采用滯后初始化 (lazy initialization) 保證字段總能被初始化,並且只在需要時才初始化。
  5. 減少類與子類之間的耦合。 當子類通過它們相應的存取成員函數訪問被繼承的字段時,它可以不影響它的任何子類,而只修改超類字段的實現方式,這樣有效地減少了超類與子類之間的耦合。存取函數減少了那種一旦超類被修改就會波及子類的“脆弱基類”的風險。
  6. 將變化封裝到字段中。如果一個或者多個字段的業務規則變化了,可以只潛在地修改存取函數,就同樣可以提供規則變化之前的功能。這一點使你很容易響應新的業務規則。
  7. 簡化並行事件。[LEA97] 指出,如果采用了基於字段值的 waits 語句,那么設置成員函數提供了一個位置可包含 notifyAll。這讓轉向並行解決方案更加容易。
  8. 名字隱藏不再是一個大問題。雖然應該避免名字隱藏,即避免賦給局部變量一個與字段相同的名字,但是始終通過存取函數訪問字段意味着可以給局部變量任何你想取的名字。不必擔心字段名的隱藏,因為你無論如何都不會直接訪問它們。

當不用存取函數時:唯一可能你不想用存取函數的時候是當執行時間最重要時。但是,這實際上很少見,因為應用程序耦合性的增加會平衡掉這樣做之后贏得的好處。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM