|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1.1 爲何要有編碼規範(Why Have Code Conventions)c++ 編碼規範對於程序員而言尤其重要,有如下幾個緣由:程序員 - 一個軟件的生命週期中,80%的花費在於維護 爲了執行規範,每一個軟件開發人員必須一致遵照編碼規範。每一個人。編程 本文檔反映的是Sun MicroSystems公司,Java語言規範中的編碼標準部分。主要貢獻者包括:Peter King,Patrick Naughton,Mike DeMoney,Jonni Kanerva,Kathy Walrath以及Scott Hommel。app 本文檔現由Scott Hommel維護,有關評論意見請發至shommel@eng.sun.com數據結構和算法 這部分列出了經常使用的文件名及其後綴。 Java程序使用下列文件後綴:
2.2 經常使用文件名(Common File Names) 經常使用的文件名包括:
一個文件由被空行分割而成的段落以及標識每一個段落的可選註釋共同組成。超過2000行的程序難以閱讀,應該儘可能避免。"Java源文件範例"提供了一個佈局合理的Java程序範例。 3.1 Java源文件(Java Source Files) 每一個Java源文件都包含一個單一的公共類或接口。若私有類和接口與一個公共類相關聯,能夠將它們和公共類放入同一個源文件。公共類必須是這個文件中的第一個類或接口。 Java源文件還遵循如下規則: - 開頭註釋(參見"開頭註釋") 3.1.1 開頭註釋(Beginning Comments) 全部的源文件都應該在開頭有一個C語言風格的註釋,其中列出類名、版本信息、日期和版權聲明: /* * Classname * * Version information * * Date * * Copyright notice */
3.1.2 包和引入語句(Package and Import Statements) 在多數Java源文件中,第一個非註釋行是包語句。在它以後能夠跟引入語句。例如: package java.awt; import java.awt.peer.CanvasPeer;
3.1.3 類和接口聲明(Class and Interface Declarations) 下表描述了類和接口聲明的各個部分以及它們出現的前後次序。參見"Java源文件範例"中一個包含註釋的例子。
4個空格常被做爲縮進排版的一個單位。縮進的確切解釋並未詳細指定(空格 vs. 製表符)。一個製表符等於8個空格(而非4個)。 儘可能避免一行的長度超過80個字符,由於不少終端和工具不能很好處理之。 注意:用於文檔中的例子應該使用更短的行長,長度通常不超過70個字符。 當一個表達式沒法容納在一行內時,能夠依據以下通常規則斷開之: - 在一個逗號後面斷開 如下是斷開方法調用的一些例子: someMethod(longExpression1, longExpression2, longExpression3, longExpression4, longExpression5); var = someMethod1(longExpression1, someMethod2(longExpression2, longExpression3));
如下是兩個斷開算術表達式的例子。前者更好,由於斷開處位於括號表達式的外邊,這是個較高級別的斷開。 longName1 = longName2 * (longName3 + longName4 - longName5) + 4 * longname6; //PREFFER longName1 = longName2 * (longName3 + longName4 - longName5) + 4 * longname6; //AVOID
如下是兩個縮進方法聲明的例子。前者是常規情形。後者若使用常規的縮進方式將會使第二行和第三行移得很靠右,因此代之以縮進8個空格 //CONVENTIONAL INDENTATION someMethod(int anArg, Object anotherArg, String yetAnotherArg, Object andStillAnother) { ... } //INDENT 8 SPACES TO AVOID VERY DEEP INDENTS private static synchronized horkingLongMethodName(int anArg, Object anotherArg, String yetAnotherArg, Object andStillAnother) { ... }
if語句的換行一般使用8個空格的規則,由於常規縮進(4個空格)會使語句體看起來比較費勁。好比: //DON’T USE THIS INDENTATION if ((condition1 && condition2) || (condition3 && condition4) ||!(condition5 && condition6)) { //BAD WRAPS doSomethingAboutIt(); //MAKE THIS LINE EASY TO MISS } //USE THIS INDENTATION INSTEAD if ((condition1 && condition2) || (condition3 && condition4) ||!(condition5 && condition6)) { doSomethingAboutIt(); } //OR USE THIS if ((condition1 && condition2) || (condition3 && condition4) ||!(condition5 && condition6)) { doSomethingAboutIt(); }
這裏有三種可行的方法用於處理三元運算表達式: alpha = (aLongBooleanExpression) ? beta : gamma; alpha = (aLongBooleanExpression) ? beta : gamma; alpha = (aLongBooleanExpression) ? beta : gamma;
Java程序有兩類註釋:實現註釋(implementation comments)和文檔註釋(document comments)。實現註釋是那些在C++中見過的,使用/*...*/和//界定的註釋。文檔註釋(被稱爲"doc comments")是Java獨有的,並由/**...*/界定。文檔註釋能夠經過javadoc工具轉換成HTML文件。 實現註釋用以註釋代碼或者實現細節。文檔註釋從實現自由(implementation-free)的角度描述代碼的規範。它能夠被那些手頭沒有源碼的開發人員讀懂。 註釋應被用來給出代碼的總括,並提供代碼自身沒有提供的附加信息。註釋應該僅包含與閱讀和理解程序有關的信息。例如,相應的包如何被創建或位於哪一個目錄下之類的信息不該包括在註釋中。 在註釋裏,對設計決策中重要的或者不是顯而易見的地方進行說明是能夠的,但應避免提供代碼中己清晰表達出來的重複信息。多餘的的註釋很容易過期。一般應避免那些代碼更新就可能過期的註釋。 注意:頻繁的註釋有時反映出代碼的低質量。當你以爲被迫要加註釋的時候,考慮一下重寫代碼使其更清晰。 註釋不該寫在用星號或其餘字符畫出來的大框裏。註釋不該包括諸如製表符和回退符之類的特殊字符。 5.1 實現註釋的格式(Implementation Comment Formats) 程序能夠有4種實現註釋的風格:塊(block)、單行(single-line)、尾端(trailing)和行末(end-of-line)。 塊註釋一般用於提供對文件,方法,數據結構和算法的描述。塊註釋被置於每一個文件的開始處以及每一個方法以前。它們也能夠被用於其餘地方,好比方法內部。在功能和方法內部的塊註釋應該和它們所描述的代碼具備同樣的縮進格式。 塊註釋之首應該有一個空行,用於把塊註釋和代碼分割開來,好比: /* * Here is a block comment. */
塊註釋能夠以/*-開頭,這樣indent(1)就能夠將之識別爲一個代碼塊的開始,而不會重排它。 /*- * Here is a block comment with some very special * formatting that I want indent(1) to ignore. * * one * two * three */
注意:若是你不使用indent(1),就沒必要在代碼中使用/*-,或爲他人可能對你的代碼運行indent(1)做讓步。 參見"文檔註釋" 5.1.2 單行註釋(Single-Line Comments) 短註釋能夠顯示在一行內,並與其後的代碼具備同樣的縮進層級。若是一個註釋不能在一行內寫完,就該採用塊註釋(參見"塊註釋")。單行註釋以前應該有一個空行。如下是一個Java代碼中單行註釋的例子: if (condition) { /* Handle the condition. */ ... }
極短的註釋能夠與它們所要描述的代碼位於同一行,可是應該有足夠的空白來分開代碼和註釋。如有多個短註釋出現於大段代碼中,它們應該具備相同的縮進。 如下是一個Java代碼中尾端註釋的例子: if (a == 2) { return TRUE; /* special case */ } else { return isPrime(a); /* works only for odd a */ }
5.1.4 行末註釋(End-Of-Line Comments) 註釋界定符"//",能夠註釋掉整行或者一行中的一部分。它通常不用於連續多行的註釋文本;然而,它能夠用來註釋掉連續多行的代碼段。如下是全部三種風格的例子: if (foo > 1) { // Do a double-flip. ... } else { return false; // Explain why here. } //if (bar > 1) { // // // Do a triple-flip. // ... //} //else { // return false; //}
5.2 文檔註釋(Documentation Comments) 注意:此處描述的註釋格式之範例,參見"Java源文件範例" 若想了解更多,參見"How to Write Doc Comments for Javadoc",其中包含了有關文檔註釋標記的信息(@return, @param, @see): http://java.sun.com/javadoc/writingdoccomments/index.html 若想了解更多有關文檔註釋和javadoc的詳細資料,參見javadoc的主頁: http://java.sun.com/javadoc/index.html 文檔註釋描述Java的類、接口、構造器,方法,以及字段(field)。每一個文檔註釋都會被置於註釋定界符/**...*/之中,一個註釋對應一個類、接口或成員。該註釋應位於聲明以前: /** * The Example class provides ... */ public class Example { ...
注意頂層(top-level)的類和接口是不縮進的,而其成員是縮進的。描述類和接口的文檔註釋的第一行(/**)不需縮進;隨後的文檔註釋每行都縮進1格(使星號縱向對齊)。成員,包括構造函數在內,其文檔註釋的第一行縮進4格,隨後每行都縮進5格。 若你想給出有關類、接口、變量或方法的信息,而這些信息又不適合寫在文檔中,則可以使用實現塊註釋(見5.1.1)或緊跟在聲明後面的單行註釋(見5.1.2)。例如,有關一個類實現的細節,應放入緊跟在類聲明後面的實現塊註釋中,而不是放在文檔註釋中。 文檔註釋不能放在一個方法或構造器的定義塊中,由於Java會將位於文檔註釋以後的第一個聲明與其相關聯。 6.1 每行聲明變量的數量(Number Per Line) 推薦一行一個聲明,由於這樣以利於寫註釋。亦即, int level; // indentation level int size; // size of table
要優於, int level, size; 不要將不一樣類型變量的聲明放在同一行,例如: int foo, fooarray[]; //WRONG!
注意:上面的例子中,在類型和標識符之間放了一個空格,另外一種被容許的替代方式是使用製表符: int level; // indentation level int size; // size of table Object currentEntry; // currently selected table entry
儘可能在聲明局部變量的同時初始化。惟一不這麼作的理由是變量的初始值依賴於某些先前發生的計算。 只在代碼塊的開始處聲明變量。(一個塊是指任何被包含在大括號"{"和"}"中間的代碼。)不要在首次用到該變量時才聲明之。這會把注意力不集中的程序員搞糊塗,同時會妨礙代碼在該做用域內的可移植性。 void myMethod() { int int1 = 0; // beginning of method block if (condition) { int int2 = 0; // beginning of "if" block ... } }
該規則的一個例外是for循環的索引變量 for (int i = 0; i < maxLoops; i++) { ... }
避免聲明的局部變量覆蓋上一級聲明的變量。例如,不要在內部代碼塊中聲明相同的變量名: int count; ... myMethod() { if (condition) { int count = 0; // AVOID! ... } ... }
6.4 類和接口的聲明(Class and Interface Declarations) 當編寫類和接口是,應該遵照如下格式規則: - 在方法名與其參數列表以前的左括號"("間不要有空格 class Sample extends Object { int ivar1; int ivar2; Sample(int i, int j) { ivar1 = i; ivar2 = j; } int emptyMethod() {} ... } - 方法與方法之間以空行分隔
每行至多包含一條語句,例如: argv++; // Correct argc--; // Correct argv++; argc--; // AVOID!
複合語句是包含在大括號中的語句序列,形如"{ 語句 }"。例以下面各段。 - 被括其中的語句應該較之複合語句縮進一個層次 一個帶返回值的return語句不使用小括號"()",除非它們以某種方式使返回值更爲顯見。例如: return; return myDisk.size(); return (size ? size : defaultSize);
7.4 if,if-else,if else-if else語句(if, if-else, if else-if else Statements) if-else語句應該具備以下格式: if (condition) { statements; } if (condition) { statements; } else { statements; } if (condition) { statements; } else if (condition) { statements; } else{ statements; }
注意:if語句老是用"{"和"}"括起來,避免使用以下容易引發錯誤的格式: if (condition) //AVOID! THIS OMITS THE BRACES {}! statement;
一個for語句應該具備以下格式: for (initialization; condition; update) { statements; }
一個空的for語句(全部工做都在初始化,條件判斷,更新子句中完成)應該具備以下格式: for (initialization; condition; update);
當在for語句的初始化或更新子句中使用逗號時,避免因使用三個以上變量,而致使複雜度提升。若須要,能夠在for循環以前(爲初始化子句)或for循環末尾(爲更新子句)使用單獨的語句。 一個while語句應該具備以下格式 while (condition) { statements; }
一個空的while語句應該具備以下格式: while (condition);
7.7 do-while語句(do-while Statements) 一個do-while語句應該具備以下格式: do { statements; } while (condition);
7.8 switch語句(switch Statements) 一個switch語句應該具備以下格式: switch (condition) { case ABC: statements; /* falls through */ case DEF: statements; break; case XYZ: statements; break; default: statements; break; }
每當一個case順着往下執行時(由於沒有break語句),一般應在break語句的位置添加註釋。上面的示例代碼中就包含註釋/* falls through */。 7.9 try-catch語句(try-catch Statements) 一個try-catch語句應該具備以下格式: try { statements; } catch (ExceptionClass e) { statements; }
一個try-catch語句後面也可能跟着一個finally語句,不論try代碼塊是否順利執行完,它都會被執行。 try { statements; } catch (ExceptionClass e) { statements; } finally { statements; }
空行將邏輯相關的代碼段分隔開,以提升可讀性。 下列狀況應該老是使用兩個空行: - 一個源文件的兩個片斷(section)之間 下列狀況應該老是使用一個空行: - 兩個方法之間 下列狀況應該使用空格: - 一個緊跟着括號的關鍵字應該被空格分開,例如: while (true) { ... } 注意:空格不該該置於方法名與其左括號之間。這將有助於區分關鍵字和方法調用。 a += c + d; a = (a + b) / (c * d); while (d++ = s++) { n++; } printSize("size is " + foo + "\n"); - for語句中的表達式應該被空格分開,例如: for (expr1; expr2; expr3) - 強制轉型後應該跟一個空格,例如: myMethod((byte) aNum, (Object) x); myMethod((int) (cp + 5), ((int) (i + 3)) + 1);
命名規範使程序更易讀,從而更易於理解。它們也能夠提供一些有關標識符功能的信息,以助於理解代碼,例如,不論它是一個常量,包,仍是類。
10 編程慣例(Programming Practices) 10.1 提供對實例以及類變量的訪問控制(Providing Access to Instance and Class Variables) 若沒有足夠理由,不要把實例或類變量聲明爲公有。一般,實例變量無需顯式的設置(set)和獲取(gotten),一般這做爲方法調用的邊緣效應 (side effect)而產生。 一個具備公有實例變量的恰當例子,是類僅做爲數據結構,沒有行爲。亦即,若你要使用一個結構(struct)而非一個類(若是java支持結構的話),那麼把類的實例變量聲明爲公有是合適的。 10.2 引用類變量和類方法(Referring to Class Variables and Methods) 避免用一個對象訪問一個類的靜態變量和方法。應該用類名替代。例如: classMethod(); //OK AClass.classMethod(); //OK anObject.classMethod(); //AVOID!
位於for循環中做爲計數器值的數字常量,除了-1,0和1以外,不該被直接寫入代碼。 10.4 變量賦值(Variable Assignments) 避免在一個語句中給多個變量賦相同的值。它很難讀懂。例如: fooBar.fChar = barFoo.lchar = 'c'; // AVOID!
不要將賦值運算符用在容易與相等關係運算符混淆的地方。例如: if (c++ = d++) { // AVOID! (Java disallows) ... }
應該寫成 if ((c++ = d++) != 0) { ... }
不要使用內嵌(embedded)賦值運算符試圖提升運行時的效率,這是編譯器的工做。例如: d = (a = b + c) + r; // AVOID!
應該寫成 a = b + c; d = a + r;
10.5 其它慣例(Miscellaneous Practices) 通常而言,在含有多種運算符的表達式中使用圓括號來避免運算符優先級問題,是個好方法。即便運算符的優先級對你而言可能很清楚,但對其餘人未必如此。你不能假設別的程序員和你同樣清楚運算符的優先級。 if (a == b && c == d) // AVOID! if ((a == b) && (c == d)) // RIGHT
設法讓你的程序結構符合目的。例如: if (booleanExpression) { return true; } else { return false; }
應該代之以以下方法: return booleanExpression;
相似地: if (condition) { return x; } return y;
應該寫作: return (condition ? x : y);
10.5.3 條件運算符"?"前的表達式(Expressions before '?' in the Conditional Operator) 若是一個包含二元運算符的表達式出如今三元運算符" ? : "的"?"以前,那麼應該給表達式添上一對圓括號。例如: (x >= 0) ? x : -x;
在註釋中使用XXX來標識某些未實現(bogus)的但能夠工做(works)的內容。用FIXME來標識某些假的和錯誤的內容。 11.1 Java源文件範例(Java Source File Example) 下面的例子,展現瞭如何合理佈局一個包含單一公共類的Java源程序。接口的佈局與其類似。更多信息參見"類和接口聲明"以及"文擋註釋"。 /* * @(#)Blah.java 1.82 99/03/18 * * Copyright (c) 1994-1999 Sun Microsystems, Inc. * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. * All rights reserved. * * This software is the confidential and proprietary information of Sun * Microsystems, Inc. ("Confidential Information"). You shall not * disclose such Confidential Information and shall use it only in * accordance with the terms of the license agreement you entered into * with Sun. */ package java.blah; import java.blah.blahdy.BlahBlah; /** * Class description goes here. * * @version 1.82 18 Mar 1999 * @author Firstname Lastname */ public class Blah extends SomeClass { /* A class implementation comment can go here. */ /** classVar1 documentation comment */ public static int classVar1; /** * classVar2 documentation comment that happens to be * more than one line long */ private static Object classVar2; /** instanceVar1 documentation comment */ public Object instanceVar1; /** instanceVar2 documentation comment */ protected int instanceVar2; /** instanceVar3 documentation comment */ private Object[] instanceVar3; /** * ...constructor Blah documentation comment... */ public Blah() { // ...implementation goes here... } /** * ...method doSomething documentation comment... */ public void doSomething() { // ...implementation goes here... } /** * ...method doSomethingElse documentation comment... * @param someParam description */ public void doSomethingElse(Object someParam) { // ...implementation goes here... } } |
出處:http://morningspace.51.net/resource/javacodeconv.html |