基于Oracle,Google,Twitter和Spring Framework的編碼標(biāo)準(zhǔn) 本文的目的是為您提供基于Oracle,Google,Twitter和Spring Framework等技術(shù)巨頭的編碼標(biāo)準(zhǔn)的"做與不做"的簡(jiǎn)要概述,換句話說(shuō),您更喜歡和避免。 您可能同意或不同意此處介紹的一些最佳做法,并且只要有某種編碼標(biāo)準(zhǔn)就可以了。 為什么首先要編碼標(biāo)準(zhǔn)?如果您使用Google進(jìn)行搜索,有很多充分的理由,下面將為您提供以下插圖 編碼標(biāo)準(zhǔn)文檔可能冗長(zhǎng)而乏味。本文從Google,Oracle,Twitter和Spring的編碼約定中挑選了一些零碎的內(nèi)容,其目的是為您提供易于理解且較無(wú)聊的做法,以使您的代碼易于閱讀和維護(hù)。 幾乎總是您會(huì)加入使用現(xiàn)有軟件的團(tuán)隊(duì),并且大多數(shù)作者很有可能離開(kāi)或切換到其他項(xiàng)目,這使您陷入困擾人類(lèi)的部分代碼。 讓我們深入了解各種編碼標(biāo)準(zhǔn)中的最佳做法。 Java源文件 關(guān)于Java源文件,以下內(nèi)容被視為最佳實(shí)踐: · 源文件長(zhǎng)度小于2,000行代碼 · 源文件的組織方式包括文檔注釋?zhuān)绦虬暶?,后跟?lèi)注釋?zhuān)纸M導(dǎo)入(最后一個(gè)靜態(tài)),類(lèi)/接口簽名等,如下所示 package com.example.model; /** * Implementation-free perspective to be read by developers * who might not necessarily have the source code at hand * * @author x,y,z * @date * @version * @copyright * */ import com.example.util.FileUtil; /* * Optional class specific comment * */ public class SomeClass { // Static variables in order of visibility public static final Integer PUBLIC_COUNT=1; static final Integer PROTECTED_COUNT=1; private static final Integer PRIVATE_COUNT=1; // Instance variables in order of visibility public String name; String postalCode; private String address; // Constructor and overloaded in sequential order public SomeClass() {} public SomeClass(String name) { this.name=name; } // Methods public String doSomethingUseful() { return "Something useful"; } // getters, setters, equals, hashCode and toString at the end }命名 類(lèi)和接口的名稱(chēng)均為CamelCase,建議使用整個(gè)單詞,并避免使用縮寫(xiě)詞/縮寫(xiě)。例如Raster類(lèi)或ImageSprite類(lèi) · 包-在com.deepSpace或com.deep_space上命名com.deepspace · 文件-名稱(chēng)為CamelCase,以.java結(jié)尾,與類(lèi)名匹配。每個(gè)文件有一個(gè)公共類(lèi),文件中有每個(gè)頂級(jí)類(lèi) · 方法-名稱(chēng)應(yīng)為混合大小寫(xiě)的動(dòng)詞,每個(gè)內(nèi)部單詞用大寫(xiě)字母表示,例如run();或runFast(); · 常量-應(yīng)該用大寫(xiě)字母" _"分隔每個(gè)單詞,例如int MIN_WIDTH=44;并且int MAX_WIDTH=99; · 變量-一個(gè)名稱(chēng),告訴程序的讀者變量代表什么,即,如果要存儲(chǔ)測(cè)試等級(jí),則選擇等級(jí)vs var1。變量名要簡(jiǎn)短,避免包含元數(shù)據(jù)。 // Prefer () - variable names short and describe what it stores int schoolId; int[] filteredSchoolIds; int[] uniqueSchooldIds; Map usersById; String value; //Avoid (x) - Too detailed variable naming int schoolIdentificationNumber; int[] userProvidedSchoolIds; int[] schoolIdsAfterRemovingDuplicates; Map idToUserMap; String valueString; 請(qǐng)記住,變量名應(yīng)該簡(jiǎn)短,并易于告訴讀者它代表什么值。用你的判斷。 傾向性和避免 格式和縮進(jìn)都是組織代碼以使其易于閱讀,其中包括間距,行長(zhǎng),換行和換行等 · 縮進(jìn)-使用2或4個(gè)空格或制表符并保持一致 · 行長(zhǎng)-取決于可讀性的影響,最多70至120個(gè)字符。消除水平滾動(dòng)和在逗號(hào)和運(yùn)算符后放置換行符的需求非常重要。 方法-以下是最佳做法清單 // Prefer () Line breaks are arbitrary and break after a comma. String downloadAnInternet(Internet internet, Tubes tubes, Blogosphere blogs, Amount bandwidth) { tubes.download(internet); } // Avoid (x) Hard to diff method args to method body String downloadAnInternet(Internet internet, Tubes tubes, Blogosphere blogs, Amount bandwidth) { tubes.download(internet); } // Prefer () Add 8 (double of 2 or 4) spaces for deep indent private static synchronized horkingLongMethodName(int anArg, Object anotherArg, String yetAnotherArg, Object andStillAnother) { ... } // Prefer () Easy scanning and extra column space. public String downloadAnInternet( Internet internet, Tubes tubes, Blogosphere blogs, Amount bandwidth) { tubes.download(internet); ... } > A unit test would have caught that 如果檢查-IMO編寫(xiě)格式正確的代碼可以使游戲作者和代碼審閱者容易發(fā)現(xiàn)打字錯(cuò)誤和錯(cuò)誤,請(qǐng)參見(jiàn)下文: // Avoid (x) Do not omit {} if (condition) statement; // Avoid (x) if (x < 0) negative(x); // Avoid (x) if (a==b && c==d) { ... } // Prefer () if ((a==b) && (c==d)) { ... } // Prefer () if (condition) { statements; } else if (condition) { statements; } else if (condition) { statements; } // Avoid (x) if ((condition1 && condition2) || (condition3 && condition4) ||!(condition5 && condition6)) { //BAD WRAPS doSomethingAboutIt(); //MAKE THIS LINE EASY TO MISS } // Prefer () if ((condition1 && condition2) || (condition3 && condition4) ||!(condition5 && condition6)) { doSomethingAboutIt(); } 三元運(yùn)算符-以下是推薦做法 alpha=(aLongBooleanExpression) ? beta : gamma; alpha=(aLongBooleanExpression) ? beta : gamma; alpha=(aLongBooleanExpression) ? beta : gamma; Switch-切換時(shí),最佳做法是 · 即使沒(méi)有代碼也總是有默認(rèn)default情況 · 使用/* falls through */表示控件屬于下一種情況 switch (condition) { case ABC: statements; /* falls through */ case DEF: statements; break; default: statements; break; } 異常消息-引發(fā)異常時(shí),這里是縮進(jìn)和縮進(jìn)不好的消息的示例。 // Avoid (x) - Not easy to read throw new IllegalStateException("Failed to process request" + request.getId() + " for user " + user.getId() + " query: '" + query.getText() + "'"); // Prefer () - Fairly easier to read throw new IllegalStateException("Failed to process" + " request " + request.getId() + " for user " + user.getId() + " query: '" + query.getText() + "'"); 迭代器和流-流變得越來(lái)越普遍,有時(shí)可能非常復(fù)雜,因此,縮進(jìn)以便于閱讀非常重要。 // Avoid (x) - Not easy to read Iterable modules=ImmutableList.builder().add(new LifecycleModule()) .add(new AppLauncherModule()).addAll(application.getModules()).build(); // Prefer () - Fairly easier to read Iterable modules=ImmutableList.builder() .add(new LifecycleModule()) .add(new AppLauncherModule()) .addAll(application.getModules()) .build(); > Just follow a coding standard — any really 聲明和分配-建議每行一個(gè)聲明,因?yàn)樗膭?lì)注釋?zhuān)缦滤尽?/p> // Prefer () int level; // indentation level int sizeMeter; // size of table // Avoid (x) in favour of above int level, sizeMeter; // Prefer () - Include unit in variable name or type long pollIntervalMs; int fileSizeGb; Amount fileSize; // Avoid (x) mixing types int foo, fooarray[]; // Avoid (x) - Do not separate with comma Format.print(System.out, “error”), exit(1); // Avoid (x) multiple assignment fooBar.fChar=barFoo.lchar='c'; // Avoid (x) embedded assignments in attempt to increase performance // or save a line. I am guilty of doing this :( d=(a=b + c) + r; // Prefer () over above a=b + c; d=a + r; // Prefer () String[] args // Avoid (x) String args[] // Prefer () Long use "L" instead of "l" to avoid confusion with 1 long timeout=3000000000L; // Avoid (x) - Hard to tell last letter is l and not 1 long timeout=3000000000l; 僅在塊的開(kāi)頭放置聲明(塊是由花括號(hào){和}包圍的代碼)。不要等到首次使用變量后再聲明它們。它可能會(huì)使笨拙的程序員感到困惑,并妨礙范圍內(nèi)的代碼可移植性。 // Prefer () declare at the beginning of the block. public void doSomething() { int whatIRepresent; // beginning of method block if (condition) { int someFlag; // beginning of “if” block … } } 同樣重要的是要避免局部聲明隱藏更高級(jí)別的聲明,并避免造成混淆,如下所示 int count; ... public void doSomething() { if (condition) { int count; // AVOID! ... } ... } 間距和換行符—避免以犧牲可讀性為代價(jià)來(lái)保存1-2行代碼的誘惑。這是有關(guān)間距和空白行的所有最佳實(shí)踐(空格確實(shí)有所作為) · 方法和Spring開(kāi)發(fā)人員之間的一(1)條空行建議在構(gòu)造函數(shù),靜態(tài)塊,字段和內(nèi)部類(lèi)之后的兩(2)條空行 · 空格鍵運(yùn)算符,即使用int foo=a + b + 1; 而非 int foo=a + b + 1; · 分隔除"."外的所有二進(jìn)制運(yùn)算符。使用空格分割 · 括號(hào)" {"出現(xiàn)在聲明語(yǔ)句或方法的同一行的末尾,右括號(hào)"}"本身以縮進(jìn)開(kāi)始 // Prefer () - Space after "while" and before "(" while (true) { ... } // Avoid (x) - Unlike above no space while(true) { ... } // Prefer () - No space between "doSomething" and "(" public void doSomething() { ... } // Avoid (x) - Unlike above space public void doSomething () { ... } // Prefer () - Add a space after an argument public void doSomething(int a, int b) { ... } // Prefer () - Space between operand and operators (i.e. +,=) a +=c + d; a=(a + b) / (c * d); while (d++=s++) { n++; }文檔和注釋 值得一提的是,幾乎所有代碼都會(huì)在其整個(gè)生命周期中進(jìn)行更改,除非您明確說(shuō)明,否則有時(shí)您或某人會(huì)試圖弄清楚打算使用復(fù)雜的代碼塊,方法或類(lèi)做什么?,F(xiàn)實(shí)幾乎總是如下 有時(shí),對(duì)復(fù)雜的代碼,方法,類(lèi)的注釋不會(huì)增加任何值或無(wú)法達(dá)到其目的。為此,通常在注釋時(shí)會(huì)發(fā)生這種情況。 注釋?xiě)?yīng)用于提供代碼概述,并提供代碼本身不容易獲得的其他信息。讓我們開(kāi)始吧。有兩種類(lèi)型的評(píng)論 實(shí)施注釋—用于注釋掉代碼或?qū)Υa的特定實(shí)現(xiàn)進(jìn)行注釋。 文檔注釋—旨在從無(wú)實(shí)現(xiàn)的角度描述代碼規(guī)范,以供可能不一定擁有源代碼的開(kāi)發(fā)人員閱讀。 注釋的頻率有時(shí)反映出代碼質(zhì)量差。當(dāng)您不得不添加評(píng)論時(shí),請(qǐng)考慮重寫(xiě)代碼以使其更清晰。 注釋的類(lèi)型 共有四(4)種實(shí)施注釋?zhuān)缦滤?/p> · 塊注釋-請(qǐng)參見(jiàn)下面的示例 · 單行注釋-當(dāng)注釋不超過(guò)一行時(shí) · 尾隨注釋-非常短的評(píng)論移到了右端 · 行尾注釋—開(kāi)始注釋?zhuān)⒗^續(xù)到換行符。它可以注釋掉整行或僅部分行。不應(yīng)在連續(xù)的多行中使用它來(lái)進(jìn)行文本注釋?zhuān)坏?,它可以在連續(xù)的多行中用于注釋掉代碼段。 // Block comment /* * Usage: Provides description of files, methods, data structures * and algorithms. Can be used at the beginning of each file and * before each method. Used for long comments that do not fit a * single line. 1 Blank line to proceed after the block comment. */ // Single line comment if (condition) { /* Handle the condition. */ ... } // Trailing comment if (a==2) { return TRUE; /* special case */ } else { return isPrime(a); /* works only for odd a */ } // End of line comment if (foo > 1) { // Do a double-flip. ... } else { return false; // Explain why here. } //if (bar > 1) { // // // Do a triple-flip. // ... //} //else // return false;文檔注釋?zhuān)碕avadoc) Javadoc是一種工具,它使用以/ **開(kāi)頭和以* /結(jié)束的注釋從Java代碼生成HTML文檔,有關(guān)Javadoc的工作方式或閱讀全文,請(qǐng)參閱Wikipedia。 這是一個(gè)Javadoc示例 /** * Returns an Image object that can then be painted on the screen. * The url argument must specify an absolute {@link URL}. The name * argument is a specifier that is relative to the url argument. * * This method always returns immediately, whether or not the * image exists. When this applet attempts to draw the image on * the screen, the data will be loaded. The graphics primitives * that draw the image will incrementally paint on the screen. * * @param url an absolute URL giving the base location of the image * @param name the location of the image, relative to the url argument * @return the image at the specified URL * @see Image */ public Image getImage(URL url, String name) { try { return getImage(new URL(url, name)); } catch (MalformedURLException e) { return null; } } 當(dāng)對(duì)具有以上代碼的代碼運(yùn)行javadoc時(shí),以上代碼將導(dǎo)致HTML如下所示 > See here for more 這是一些關(guān)鍵標(biāo)記,可用于增強(qiáng)生成的Java文檔的質(zhì)量。 @author => @author Raf @code => {@code AC} @deprecated=> @deprecated deprecation-message @exception => @exception IOException thrown when @link => {@link package.class#member label} @param => @param parameter-name description @return => What the method returns @since => To indicate the version when a publicly accessible method is added 有關(guān)完整列表和更詳細(xì)的說(shuō)明,請(qǐng)參見(jiàn) oracle/technetwork/java/javase/tech/index-137868.html Twitter的編碼標(biāo)準(zhǔn)建議不要使用@author標(biāo)簽 代碼可以在其生命周期內(nèi)無(wú)數(shù)次換手,并且源文件的原始作者在經(jīng)過(guò)多次迭代后常常是無(wú)關(guān)緊要的。我們發(fā)現(xiàn)最好信任提交歷史記錄和OWNERS文件來(lái)確定代碼主體的所有權(quán)。 以下示例說(shuō)明了如何按照Twitter的編碼標(biāo)準(zhǔn)中的描述撰寫(xiě)有見(jiàn)地的文檔注釋 // Bad. // - The doc tells nothing that the method declaration didn't. // - This is the 'filler doc'. It would pass style checks, but doesn't help anybody. /** * Splits a string. * * @param s A string. * @return A list of strings. */ List split(String s); // Better. // - We know what the method splits on. // - Still some undefined behavior. /** * Splits a string on whitespace. * * @param s The string to split. An {@code null} string is treated as an empty string. * @return A list of the whitespace-delimited parts of the input. */ List split(String s); // Great. // - Covers yet another edge case. /** * Splits a string on whitespace. Repeated whitespace characters * are collapsed. * * @param s The string to split. An {@code null} string is treated as an empty string. * @return A list of the whitespace-delimited parts of the input. */ List split(String s); 寫(xiě)注釋時(shí)專(zhuān)業(yè)很重要的 // Avoid (x) // I hate xml/soap so much, why can't it do this for me!? try { userId=Integer.parseInt(xml.getField("id")); } catch (NumberFormatException e) { ... } // Prefer () // TODO(Jim): Tuck field validation away in a library. try { userId=Integer.parseInt(xml.getField("id")); } catch (NumberFormatException e) { ... } 而且重要的是要記住,除非實(shí)現(xiàn)已更改,否則不要記錄重寫(xiě)的方法。 還有幾點(diǎn)需要牢記 · 避免使用通配符導(dǎo)入-如Twitter的編碼標(biāo)準(zhǔn)中所述,它使類(lèi)的來(lái)源變得不清楚。我在一個(gè)由Eclipse和IntelliJ用戶組成的團(tuán)隊(duì)中工作,我發(fā)現(xiàn)Eclipse刪除了通配符導(dǎo)入,而IntelliJ引入了通配符。可能有一個(gè)關(guān)閉它的選項(xiàng),只是想指出兩者的默認(rèn)值。 · 覆蓋時(shí)始終使用@Override注解 · 鼓勵(lì)在字段或方法返回null時(shí)使用@Nullable · 在將來(lái)的工作中使用特殊評(píng)論,不要忘了給自己留下參考,以便其他人知道是誰(shuí)提出他們的問(wèn)題,而不是猜測(cè),刪除它或檢查git blame以查找添加它的人。一些IDE(例如Eclipse和IntelliJ)也有助于列出這些IDE,以便于訪問(wèn)和提醒。 //FIXME (Raf): An actionable message describe what needs to be done //TODO (Raf): An actionable message describe what needs to be done 最終的目的是編寫(xiě)使將來(lái)的作者和維護(hù)者的生活變得輕松的代碼。
> The end game |
|
來(lái)自: 心悅仰空 > 《待分類(lèi)》