1、盡量使用接口,然后使用類實現接口,以提高程序的靈活性。 2、一行不要超過80個字符 3、盡量不要手工更改計算機生成的代碼,若必須修改,一定要改成和計算機生成的代碼風格一樣。 4、關鍵的語句(包括聲明關鍵的變量)必須要寫注釋。 5、建議局部變量在最接近使用它的地方聲明。 6、不要使用goto系列語句,除非是用在跳出深層循環時。 7、避免寫超過5個參數的方法。如果要傳遞多個參數,則使用結構。 8、避免書寫代碼量過大的try…catch模塊。 9、避免在同一個文件中放置多個類。 10、生成和構建一個長的字符串時,一定要使用StringBuilder類型,而不是string類型。 11、switch語句一定要有default語句來處理意外情況。 12、對於if語句,應該使用一對“{}”把語句塊包含起來。 13、盡量不使用this關鍵字引用。
第一命名:
類名的話,使用大駝峰,方法名和變量名采用小駝峰的樣式. 最好能夠見名知意 例如
public class Demo { public void demoBind() { } }
string strUserName;
Java代碼規范
本Java代碼規范以SUN的標准Java代碼規范為基礎,為適應我們公司的實際需要,可能會做一些修改。本文檔中沒有說明的地方,請參看SUN Java標准代碼規范。如果兩邊有沖突,以本文檔為准。
1. 標識符命名規范
1.1 概述
標識符的命名力求做到統一、達意和簡潔。
1.1.1 統一
統一是指,對於同一個概念,在程序中用同一種表示方法,比如對於供應商,既可以用supplier,也可以用provider,但是我們只能選定一個使用,至少在一個Java項目中保持統一。統一是作為重要的,如果對同一概念有不同的表示方法,會使代碼混亂難以理解。即使不能取得好的名稱,但是只要統一,閱讀起來也不會太困難,因為閱讀者只要理解一次。
1.1.2 達意
達意是指,標識符能准確的表達出它所代表的意義,比如: newSupplier, OrderPaymentGatewayService等;而 supplier1, service2,idtts等則不是好的命名方式。准確有兩成含義,一是正確,而是豐富。如果給一個代表供應商的變量起名是 order,顯然沒有正確表達。同樣的,supplier1, 遠沒有targetSupplier意義豐富。
1.1.3 簡潔
簡潔是指,在統一和達意的前提下,用盡量少的標識符。如果不能達意,寧願不要簡潔。比如:theOrderNameOfTheTargetSupplierWhichIsTransfered 太長, transferedTargetSupplierOrderName則較好,但是transTgtSplOrdNm就不好了。省略元音的縮寫方式不要使用,我們的英語往往還沒有好到看得懂奇怪的縮寫。
1.1.4 駱駝法則
Java中,除了包名,靜態常量等特殊情況,大部分情況下標識符使用駱駝法則,即單詞之間不使用特殊符號分割,而是通過首字母大寫來分割。比如: SupplierName, addNewContract,而不是 supplier_name, add_new_contract。
1.1.5 英文 vs 拼音
盡量使用通俗易懂的英文單詞,如果不會可以向隊友求助,實在不行則使用漢語拼音,避免拼音與英文混用。比如表示歸檔,用archive比較好, 用pigeonhole則不好,用guiDang尚可接受。
1.2 包名
使用小寫字母如 com.xxx.settlment
,不要 com.xxx.Settlement
單詞間不要用字符隔開,比如 com.xxx.settlment.jsfutil
,而不要com.xxx.settlement.jsf_util
1.3 類名
1.3.1 首字母大寫
類名要首字母大寫,比如 SupplierService, PaymentOrderAction;不要 supplierService, paymentOrderAction.
1.3.2 后綴
類名往往用不同的后綴表達額外的意思,如下表:
后綴名 | 意義 | 舉例 |
Service | 表明這個類是個服務類,里面包含了給其他類提同業務服務的方法 | PaymentOrderService |
Impl | 這個類是一個實現類,而不是接口 | PaymentOrderServiceImpl |
Inter | 這個類是一個接口 | LifeCycleInter |
Dao | 這個類封裝了數據訪問方法 | PaymentOrderDao |
Action | 直接處理頁面請求,管理頁面邏輯了類 | UpdateOrderListAction |
Listener | 響應某種事件的類 | PaymentSuccessListener |
Event | 這個類代表了某種事件 | PaymentSuccessEvent |
Servlet | 一個Servlet | PaymentCallbackServlet |
Factory | 生成某種對象工廠的類 | PaymentOrderFactory |
Adapter | 用來連接某種以前不被支持的對象的類 | DatabaseLogAdapter |
Job | 某種按時間運行的任務 | PaymentOrderCancelJob |
Wrapper | 這是一個包裝類,為了給某個類提供沒有的能力 | SelectableOrderListWrapper |
Bean | 這是一個POJO | MenuStateBean |
1.4 方法名
首字母小寫,如 addOrder() 不要 AddOrder()
動詞在前,如 addOrder(),不要orderAdd()
動詞前綴往往表達特定的含義,如下表:
前綴名 | 意義 | 舉例 |
create | 創建 | createOrder() |
delete | 刪除 | deleteOrder() |
add | 創建,暗示新創建的對象屬於某個集合 | addPaidOrder() |
remove | 刪除 | removeOrder() |
init或則initialize | 初始化,暗示會做些諸如獲取資源等特殊動作 | initializeObjectPool |
destroy | 銷毀,暗示會做些諸如釋放資源的特殊動作 | destroyObjectPool |
open | 打開 | openConnection() |
close | 關閉 | closeConnection()< |
read | 讀取 | readUserName() |
write | 寫入 | writeUserName() |
get | 獲得 | getName() |
set | 設置 | setName() |
prepare | 准備 | prepareOrderList() |
copy | 復制 | copyCustomerList() |
modity | 修改 | modifyActualTotalAmount() |
calculate | 數值計算 | calculateCommission() |
do | 執行某個過程或流程 | doOrderCancelJob() |
dispatch | 判斷程序流程轉向 | dispatchUserRequest() |
start | 開始 | startOrderProcessing() |
stop | 結束 | stopOrderProcessing() |
send | 發送某個消息或事件 | sendOrderPaidMessage() |
receive | 接受消息或時間 | receiveOrderPaidMessgae() |
respond | 響應用戶動作 | responseOrderListItemClicked() |
find | 查找對象 | findNewSupplier() |
update | 更新對象 | updateCommission() |
find方法在業務層盡量表達業務含義,比如 findUnsettledOrders(),查詢未結算訂單,而不要findOrdersByStatus()。 數據訪問層,find,update等方法可以表達要執行的sql,比如findByStatusAndSupplierIdOrderByName(Status.PAID, 345)
1.5 域(field)名
1.5.1 靜態常量
全大寫用下划線分割,如
public static find String ORDER_PAID_EVENT = "ORDER_PAID_EVENT";
1.5.2 枚舉
全大寫,用下划線分割,如
public enum Events {
ORDER_PAID,
ORDER_CREATED
}
1.5.3 其他
首字母小寫,駱駝法則,如:
public String orderName;
1.6 局部變量名
參數和局部變量名首字母小寫,駱駝法則。盡量不要和域沖突,盡量表達這個變量在方法中的意義。
2. 代碼格式
用空格字符縮進源代碼,不要用tab,每個縮進4個空格。
2.1 源文件編碼
源文件使用utf-8編碼,結尾用unix n 分格。
2.2 行寬
行寬度不要超過130。
2.3 包的導入
刪除不用的導入,盡量不要使用整個包的導入。在eclipse下經常使用快捷鍵 ctrl+shift+o 修正導入。
2.4 類格式
2.5 域格式
每行只能聲明一個域。
域的聲明用空行隔開。
2.5 方法格式
2.6 代碼塊格式
2.6.1 縮進風格
大括號的開始在代碼塊開始的行尾,閉合在和代碼塊同一縮進的行首,例如:
package com.test;
public class TestStyle extends SomeClass implements AppleInter, BananaInter {
public static final String THIS_IS_CONST = "CONST VALUE";
private static void main(String[] args) {
int localVariable = 0;
}
public void compute(String arg) {
if (arg.length() > 0) {
System.out.println(arg);
}
for (int i = 0; i < 10; i++) {
System.out.println(arg);
}
while (condition) {
}
do {
otherMethod();
} while (condition);
switch (i) {
case 0:
callFunction();
break;
case 1:
callFunctionb();
break;
default:
break;
}
}
}
2.6.2 空格的使用
2.6.2.1 表示分割時用一個空格
不能這樣:
if ( a > b ) {
//do something here
};
2.6.2.2 二元三元運算符兩邊用一個空格隔開
如下:
a + b = c;
b - d = e;
return a == b ? 1 : 0;
不能如下:
a+b=c;
b-d=e;
return a==b?1:0;
2.6.2.3 逗號語句后如不還行,緊跟一個空格
如下:
call(a, b, c);
不能如下:
call(a,b,c);
2.6.3 空行的使用
空行可以表達代碼在語義上的分割,注釋的作用范圍,等等。將類似操作,或一組操作放在一起不用空行隔開,而用空行隔開不同組的代碼, 如圖:
order = orderDao.findOrderById(id);
//update properties
order.setUserName(userName);
order.setPrice(456);
order.setStatus(PAID);
orderService.updateTotalAmount(order);
session.saveOrUpdate(order);
上例中的空行,使注釋的作用域很明顯.
- 連續兩行的空行代表更大的語義分割。
- 方法之間用空行分割
- 域之間用空行分割
- 超過十行的代碼如果還不用空行分割,就會增加閱讀困難
3. 注釋規范
3.1 注釋 vs 代碼
- 注釋宜少二精,不宜多而濫,更不能誤導
- 命名達意,結構清晰, 類和方法等責任明確,往往不需要,或者只需要很少注釋,就可以讓人讀懂;相反,代碼混亂,再多的注釋都不能彌補。所以,應當先在代碼本身下功夫。
- 不能正確表達代碼意義的注釋,只會損害代碼的可讀性。
- 過於詳細的注釋,對顯而易見的代碼添加的注釋,羅嗦的注釋,還不如不寫
。
- 注釋要和代碼同步,過多的注釋會成為開發的負擔
- 注釋不是用來管理代碼版本的,如果有代碼不要了,直接刪除,svn會有記錄的,不要注釋掉,否則以后沒人知道那段注釋掉的代碼該不該刪除。
3.2 Java Doc
表明類、域和方法等的意義和用法等的注釋,要以javadoc的方式來寫。Java Doc是個類的使用者來看的,主要介紹 是什么,怎么用等信息。凡是類的使用者需要知道,都要用Java Doc 來寫。非Java Doc的注釋,往往是個代碼的維護者看的,着重告述讀者為什么這樣寫,如何修改,注意什么問題等。 如下:
/**
* This is a class comment
*/
public class TestClass {
/**
* This is a field comment
*/
public String name;
/**
* This is a method comment
*/
public void call() {
}
}
3.3 塊級別注釋
3.3.1 塊級別注釋,單行時用 //, 多行時用 /* .. */。
3.3.2 較短的代碼塊用空行表示注釋作用域
3.3.3 較長的代碼塊要用
/*------ start: ------*/
和
/*-------- end: -------*/
包圍
如:
/*----------start: 訂單處理 ------- */
//取得dao
OrderDao dao = Factory.getDao("OrderDao");
/* 查詢訂單 */
Order order = dao.findById(456);
//更新訂單
order.setUserName("uu");
order.setPassword("pass");
order.setPrice("ddd");
orderDao.save(order);
/*----------end: 訂單處理 ------- */
3.3.4 可以考慮使用大括號來表示注釋范圍
使用大括號表示注釋作用范圍的例子:
/*----------訂單處理 ------- */
{
//取得dao
OrderDao dao = Factory.getDao("OrderDao");
/* 查詢訂單 */
Order order = dao.findById(456);
//更新訂單
order.setUserName("uu");
order.setPassword("pass");
order.setPrice("ddd");
orderDao.save(order);
}
3.4 行內注釋
行內注釋用 // 寫在行尾
4 最佳實踐和禁忌
4.1 每次保存的時候,都讓你的代碼是最美的
程序員都是懶惰的,不要想着等我完成了功能,再來優化代碼的格式和結構,等真的把功能完成,很少有人會再願意回頭調整代碼。
4.2 使用log而不是System.out.println()
log可以設定級別,可以控制輸出到哪里,容易區分是在代碼的什么地方打印的,而System.out.print則不行。而且,System.out.print的速度很慢。所以,除非是有意的,否則,都要用log。至少在提交到svn之前把System.out.print換成log。
4.3 每個if while for等語句,都不要省略大括號{}
看下面的代碼:
if (a > b)
a++;
如果在以后維護的時候,需要在a > b 時,把b++,一步小心就會寫成:
if (a > b)
a++;
b++;
這樣就錯了,因為無論a和b是什么關系,b++都會執行。 如果一開始就這樣寫:
if (a > b) {
a++;
}
相信沒有哪個笨蛋會把b++添加錯的。而且,這個大括號使作用范圍更明顯,尤其是后面那行很長要折行時。
4.4 善用TODO:
在代碼中加入 //TODO: ,大部分的ide都會幫你提示,讓你知道你還有什么事沒有做。比如:
if (order.isPaid()) {
//TODO: 更新訂單
}
4.5 在需要留空的地方放一個空語句或注釋,告述讀者,你是故意的
比如:
if (!exists(order)) {
;
}
或:
if (!exists(order)) {
//nothing to do
}
4.6 不要再對boolean值做true false判斷
比如:
if (order.isPaid() == true) {
// Do something here
}
不如寫成:
if (order.isPaid()) {
//Do something here
}
后者讀起來就很是 if order is paid, .... 要比 if order's isPaid method returns true, … 更容易理解
4.7 減少代碼嵌套層次
代碼嵌套層次達3層以上時,一般人理解起來都會困難。下面的代碼是一個簡單的例子:
public void demo(int a, int b, int c) {
if (a > b) {
if (b > c) {
doJobA();
} else if (b < c) {
doJobB()
}
} else {
if (b > c) {
if (a < c) {
doJobC();
}
}
}
}
減少嵌套的方法有很多:
- 合並條件
- 利用 return 以省略后面的else
- 利用子方法
比如上例,合並條件后成為:
public void demo(int a, int b, int c) {
if (a > b && b > c) {
doJobA();
}
if (a > b && c > b) {
doJobB();
}
if (a <= b && c < b && a < c) {
doJobC();
}
}
如果利用return 則成為:
public void demo(int a, int b, int c) {
if (a > b) {
if (b > c) {
doJobA();
return;
}
doJobB()
return;
}
if (b > c) {
if (a < c) {
doJobC();
}
}
}
利用子方法,就是將嵌套的程序提取出來放到另外的方法里。
4.8 程序職責單一
關注點分離是軟件開發的真理。人類自所以能夠完成復雜的工作,就是因為人類能夠將工作分解到較小級別的任務上,在做每個任務時關注更少的東西。讓程序單元的職責單一,可以使你在編寫這段程序時關注更少的東西,從而降低難度,減少出錯。
4.9 變量的聲明,初始化和被使用盡量放到一起
比方說如下代碼:
int orderNum= getOrderNum();
//do something withou orderNum here
call(orderNum);
上例中的注釋處代表了一段和orderNum不相關的代碼。orderNum的聲明和初始化離被使用的地方相隔了很多行的代碼,這樣做不好,不如這樣:
//do something withou orderNum here
int orderNum= getOrderNum();
call(orderNum);
4.10 縮小變量的作用域
能用局部變量的,不要使用實例變量,能用實例變量的,不要使用類變量。變量的生存期越短,以為着它被誤用的機會越小,同一時刻程序員要關注的變量的狀態越少。實例變量和類變量默認都不是線程安全的,局部變量是線程安全的。比如如下代碼:
public class OrderPayAction{
private Order order;
public void doAction() {
order = orderDao.findOrder();
doJob1();
doJob2();
}
private void doJob1() {
doSomething(order);
}
private void doJob2() {
doOtherThing(order);
}
}
上例中order只不過擔當了在方法間傳遞參數之用,用下面的方法更好:
public class OrderPayAction{
public void doAction() {
order = orderDao.findOrder();
doJob1(order);
doJob2(order);
}
private void doJob1(Order order) {
doSomething(order);
}
private void doJob2(Order order) {
doOtherThing(order);
}
}
4.11 盡量不要用參數來帶回方法運算結果
比如:
public void calculate(Order order) {
int result = 0;
//do lots of computing and store it in the result
order.setResult(result);
}
public void action() {
order = orderDao.findOrder();
calculate(order);
// do lots of things about order
}
例子中calculate方法通過傳入的order對象來存儲結果, 不如如下寫:
public int calculate(Order order) {
int result = 0;
//do lots of computing and store it in the result
return result;
}
public void action() {
order = orderDao.findOrder();
order.setResult(calculate(order));
// do lots of things about order
}