簡介
多年來,作為一名軟件開發者和顧問,我看到過各種程序語言編寫的大量代碼。其中有書寫優雅的,也有書寫丑陋的,不幸的是很多代碼都屬於後者。我希望說服你和我的開發伙伴我們應該在代碼風格上給予更多的關注,就像我們關注用戶界面和應用程序的其它部分那樣。這一系列由兩部分組成,在第一部分中,我將解釋為什麼我們應該關心代碼看起來到底是什麼樣子,並向你展示良好Java風格的一些基本要素。
為什麼風格如此重要
雖然Java是用來寫程序而不是寫散文的,但它也是用來表達思想和想法的。而且,除了傳遞信息,這些思想和想法也必須確實在解決一些問題。也許你會顧慮好的風格或許會像是在浪費時間,但它可以讓我們在代碼中表達的思想和想法格外的清晰。
這裡是使用良好風格的一些理由[來自"Java Code Conventions," Sun Microsystems]:
一個軟件產品一生80%的花費是在維護上。
任何軟件都幾乎不可能一生都由軟件的原作者來維護。
好的風格能夠提高軟件代碼的可維護性。
如果軟件還附帶源碼的話,那它應該像產品的其它部分那樣結構良好,清晰,專業。
以良好的風格編寫代碼還有下面這些好處:
提高代碼的可閱讀性,連貫性和一致性,這樣使代碼容易理解和維護。
易於跟蹤和調試,因為代碼是清晰和連貫的。
易於從你或別的程序員停止的地方繼續編寫代碼,特別是經過較長的一段時間以後。
提高代碼指南的價值,因為參與者可以更加集中注意力去了解代碼正在做什麼。
一般原則
以良好的風格編寫Java並不困難,但確實需要注意細節。這裡是一些應該遵守的一般原則:
使代碼清晰並易於閱讀。
使代碼一致。
使用明顯的標識符。
有邏輯地組織文件和類。
每個文件只有一個類(不包括內部類)。
最大行寬在80-90個字符之間。
使用空格和(或)其它易於判斷的分隔符。
縮進使用空格而不是制表符。
制表符 vs. 空格
制表符 vs. 空格是一個有關編寫代碼的嚴謹問題,我並不想讓你認為只有一種正確方式。我贊成使用空格是因為它確保我的代碼在我的編輯器裡和在你的編輯器裡看起來一樣,反之亦然。如果你感覺使用空格而不是制表符“就是不對”,那麼就用制表符吧。
大括號和縮進
縮進風格(參看,Raymond, "Indent Style")或者大括號("{" 和 "}")和相關的代碼縮進是另一個關於編寫代碼的嚴謹問題。像Java這種C風格的編程語言,有很多種縮進風格,並且我也不想說它們其中的哪一種就更好一些。在這篇文章的大部分示例代碼中,我使用人們常說的K&R風格。如果你不喜歡K&R,那就用另一種風格好了。
注釋
你可以有兩種類型的注釋放到你的Java代碼中:Javadoc注釋(也叫文檔注釋)和實現注釋。Javadoc注釋可以用javadoc工具提取並產生API文檔。實現注釋用來解釋代碼的“如何”和“為什麼”。使用下面的原則來注釋你的Java代碼。
在任何允許使用Javadoc注釋的地方使用Javadoc注釋(最起碼用在類和方法上)。
使用塊注釋而不是行尾(拖尾)注釋,除了一些特殊情況,比如變量的聲明。
而且,要記住好的注釋總是有幫助的;而壞的注釋卻是令人討厭的。
例1. 壞的注釋風格。
// applyRotAscii() -- Apply ASCII ROT
private void applyRotAscii(){
try{
int rotLength = Integer.parseInt(rotationLengthField.getText().trim()); // get rot len
RotAscii cipher = new RotAscii(rotLength); // new cipher
textArea.setText(cipher.transform(textArea.getText())); // transform
}catch(Exception ex){
/* Show exception */
ExceptionDialog.show(this, "Invalid rotation length: ", ex); }
}
例2. 好的注釋風格。
/**
* Apply the ASCII rotation cipher to the user's text. The length is retrieved
* from the rotation length field, and the user's text is retrieved from the
* text area.
*
* @author Thornton Rose
*/
private void applyRotAscii() {
int rotLength = 0; // rotation length
RotAscii cipher = null; // ASCII rotation cipher
try {
// Get rotation length field and convert to integer.
rotLength = Integer.parseInt(rotationLengthField.getText().trim());
// Create ASCII rotation cipher and transform the user's text with it.
cipher = new RotAscii(rotLength);
textArea.setText(cipher.transform(textArea.getText()));
} catch(Exception ex) {
// Report the exception to the user.
ExceptionDialog.show(this, "Invalid rotation length: ", ex);
}
}
塊和聲明
使用下面的原則來寫塊和聲明:
每行只放置一個聲明。
控制聲明的時候總是使用大括號(比如,'if')。
考慮在塊結束的地方做注釋(比如,} //end if),特別是那些長的或者嵌套的塊。
把各種變量的聲明放在塊的開頭。
總是初始化變量。
如果想做完美主義者,左對齊變量名。
switch塊中縮進case子句。
操作符的前後分別加上空格。
使用if,for,或者while的時候,在"("前面加上空格。
在表達式中使用空格和圓括號以提高可閱讀性。---www.bianceng.cn
'for'循環中的變量在應用“把各種變量的聲明放在塊的開頭”的原則時是個例外。循環變量應該在for語句的初始化部分進行聲明,比如,for(int i = 0; ...)
在塊結束的地方放置一個聲明有助於你捕捉到意外刪除的結束大括號。有時候,在一個巨大的文件中要想找到它們真的會把你逼瘋的。
例3. 壞的塊風格。
try{
for(int i=0;i<5;i++){
...
}
int threshold=calculateThreshold();
float variance=(threshold*2.8)-1;
int c=0;
if (threshold<=15) c=calculateCoefficient();
switch(c){
case 1: setCeiling(c*2); break;
case 2: setCeiling(c*3); break;
else: freakOut();
}
}catch(Exception ex){ ... }
例4. 好的塊風格。
try {
int threshold = 0;
float variance = 0.0;
int coefficient = 0;
// Prepare 5 cycles.
for (int i = 0; i < 5; i ++){
prepareCycle(i);
}
// Calculate the threshold and variance.
threshold = calculateThreshold();
variance = (threshold * 2.8) - 1;
// If the threshold is less than the maximum, calculate the coefficient.
// Otherwise, throw an exception.
if (threshold <= MAX_THRESHOLD) {
coefficient = calculateCoefficient();
} else {
throw new RuntimeException("Threshold exceeded!");
}
// Set the ceiling based on the coefficient.
switch (coefficient) {
case 1:
setCeiling(coefficient * 2);
break;
case 2:
setCeiling(coefficient * 3);
break;
else:
freakOut();
} // end switch
} catch(Exception ex) {
...
} // end try