Android代碼風(fēng)格

貢獻(xiàn)者的代碼風(fēng)格

下面的代碼樣式是嚴(yán)格的規(guī)則莹桅,而不是準(zhǔn)則或建議。不符合這些規(guī)則的Android應(yīng)用通常不會(huì)被接受。我們認(rèn)識(shí)到珊擂,并非所有現(xiàn)有代碼都遵循這些規(guī)則,但我們期望所有新代碼都符合费变。

Java語言規(guī)則


Android遵循標(biāo)準(zhǔn)的Java編碼規(guī)則以及下面描述的附加規(guī)則摧扇。

不要忽略異常

可能很容易編寫完全忽略異常的代碼,例如:

void setServerPort(String value) {
    try {
        serverPort = Integer.parseInt(value);
    } catch (NumberFormatException e) { }
}

切勿如此挚歧。雖然你可能認(rèn)為你的代碼永遠(yuǎn)不會(huì)出現(xiàn)這個(gè)錯(cuò)誤或者處理這個(gè)錯(cuò)誤并不重要扛稽,但這樣忽略異常將埋下一顆地雷,其他人某一天可能會(huì)觸發(fā)它滑负。你必須以合理的方式在代碼中處理每一個(gè)異常在张,方式上具體情況具體處理。
你應(yīng)當(dāng)為你寫出一個(gè)空的catch語句塊時(shí)感到驚恐矮慕。即便有時(shí)就得這么處理帮匾,但也不應(yīng)心安理得。寫Java代碼時(shí)痴鳄,你不應(yīng)當(dāng)逃避驚恐感瘟斜。——James Gosling
可接受的替代方案(按優(yōu)先順序)是:

  • 將異常拋出給方法的調(diào)用者。
    void setServerPort(String value) throws NumberFormatException {
        serverPort = Integer.parseInt(value);
    }
  • 拋出一個(gè)適合你的抽象層次的新異常痪寻。
    void setServerPort(String value) throws ConfigurationException {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            throw new ConfigurationException("Port " + value + " is not valid.");
        }
    }
  • 優(yōu)雅地處理錯(cuò)誤并在catch {}塊中替換一個(gè)合適的值螺句。
    /** Set port. If value is not a valid number, 80 is substituted. */

    void setServerPort(String value) {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            serverPort = 80;  // default port for server
        }
    }
  • 捕獲異常并拋出一個(gè)新的RuntimeException。這是比較危險(xiǎn)的槽华,除非你確定導(dǎo)致這個(gè)錯(cuò)誤的事件屬于程序崩潰壹蔓。
    /** Set port. If value is not a valid number, die. */

    void setServerPort(String value) {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            throw new RuntimeException("port " + value " is invalid, ", e);
        }
    }
 > **注意** 將原異常作為參數(shù)創(chuàng)建RuntimeException。如果代碼必須在Java 1.3上編譯猫态,那么你不得不忽略作為原因的原始異常佣蓉。
  • 作為最后的手段,如果確定忽略異常是恰當(dāng)?shù)那籽敲纯梢院雎运缕荆仨氉⑨屢粋€(gè)很好的理由為什么忽略:
    /** If value is not a valid number, original port number is used. */
    void setServerPort(String value) {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            // Method is documented to just ignore invalid user input.
            // serverPort will just be unchanged.
        }
    }

不要捕捉基類異常

有時(shí)候很容易懶惰到這樣捕捉異常:

try {
    someComplicatedIOFunction();        // may throw IOException
    someComplicatedParsingFunction();   // may throw ParsingException
    someComplicatedSecurityFunction();  // may throw SecurityException
    // phew, made it all the way
} catch (Exception e) {                 // I'll just catch all exceptions
    handleError();                      // with one generic handler!
}

切勿如此。在幾乎所有情況下义辕,捕獲基類異诚罕辏或Throwable(最好不是Throwable,因?yàn)樗ㄥe(cuò)誤異常)是不合適的灌砖。這非常危險(xiǎn)璧函,因?yàn)檫@意味著你會(huì)捕捉那些本應(yīng)在應(yīng)用級(jí)被處理的非預(yù)期的異常(包括像ClassCastException這樣的運(yùn)行時(shí)異常)傀蚌。它忽略了處理異常時(shí)的異常類型,也就是如果別人在你調(diào)用的代碼中加入了一種新的類型的異常蘸吓,編譯器就無法幫你區(qū)別處理這個(gè)新的類型的異常善炫,而在大多數(shù)情況下,不應(yīng)以同樣的方式處理不同類型的異常库继。
這條規(guī)則也有個(gè)罕見的例外箩艺,在你希望捕獲各種錯(cuò)誤(防止它們出現(xiàn)在UI中,或者保持后續(xù)的工作繼續(xù)運(yùn)行)的測試代碼和頂層代碼中宪萄,你可以捕捉并恰當(dāng)?shù)靥幚砘惍惓#ɑ騎hrowable)艺谆。慎重而為,并注解出為何此處這么做是安全的拜英。
捕獲泛型異常的替代方案:

  • 每個(gè)try語句之后分類型捕獲每一個(gè)異常静汤,方法雖笨,但是卻要優(yōu)于捕獲基類異常居凶,避免在catch塊中代碼過度重復(fù)撒妈。
  • 重構(gòu)代碼,拆分單個(gè)try塊的內(nèi)容排监,換成多個(gè)try塊來捕獲異常。通過拆分輸入輸出與解析來區(qū)別處理捕獲的異常杰捂。
  • 重新拋出異常舆床。多數(shù)時(shí)候你并不需要捕獲這個(gè)級(jí)別的異常,就讓方法拋出來即可嫁佳。
    記装ざ印:把異常當(dāng)朋友吧!當(dāng)編譯器提示你沒有捕獲異常時(shí)蒿往,不用皺眉盛垦。微笑:編譯器不過是輔助你捕獲代碼中的運(yùn)行錯(cuò)誤。

不要使用Finalizers

Finalizers可以讓你在對(duì)象被垃圾回收時(shí)執(zhí)行一段代碼瓤漏。雖然他非常便于進(jìn)行資源清理(尤其是外部資源)腾夯,但是無法保證什么時(shí)候會(huì)調(diào)用它(或者甚至馬上就會(huì)調(diào)用)。
Android并不使用Finalizers蔬充。大多數(shù)情況下蝶俱,你可在一個(gè)擁有較好的異常捕獲的Finalizers中執(zhí)行你想要的操作。如果你的確需要它饥漫,定義一個(gè)close()(或類似的)方法并注釋出這個(gè)方法需要在什么時(shí)候被調(diào)用(可參見InputStream)榨呆。這種情況下,并不要求但可以適當(dāng)?shù)卮蛴∫恍┖喍痰娜罩鞠⒂苟樱?dāng)然也不能日志洪泛积蜻。

完整的導(dǎo)入

當(dāng)你想要使用foo包的Bar類時(shí)闯割,以下是兩種可能的導(dǎo)入方式:

  • import foo.*;
    潛在地減少import語句的數(shù)量。
  • import foo.Bar;
    能確切地指出什么類被使用了并且對(duì)維護(hù)者來說可讀性更高竿拆。

Android代碼中全部使用import foo.Bar;的導(dǎo)入方式宙拉。另一種方案在Java標(biāo)準(zhǔn)庫(java.util.*java.io.*等)與單元測試代碼(junit.framework.*)上存在顯式異常如输。

Java庫規(guī)則


在使用Android的Java庫和工具上存在一些約定鼓黔。在某些情況下,這些約定出現(xiàn)了重大的改變不见,較早的代碼可能仍然使用一些已棄用的模式或庫澳化。對(duì)于現(xiàn)成的代碼可以繼續(xù)現(xiàn)有的風(fēng)格,但對(duì)于新創(chuàng)建的組件時(shí)稳吮,就不要再使用已棄用的庫了缎谷。

Java風(fēng)格規(guī)則


使用標(biāo)準(zhǔn)的Javadoc注釋

每個(gè)文件應(yīng)在頂部有一個(gè)版權(quán)聲明,其后是package和import語句(每個(gè)塊由空行分隔)灶似,最后是類或接口聲明列林。在Javadoc注釋中,需描述類或接口的作用酪惭。

/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.internal.foo;

import android.os.Blah;
import android.view.Yada;

import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * Does X and Y and provides an abstraction for Z.
 */

public class Foo {
    ...
}

你寫的每一個(gè)類和重要的公共方法必須包含一個(gè)Javadoc注釋希痴,至少需要一句話的描述。句式以動(dòng)詞開始春感。
例如:

/** Returns the correctly rounded positive square root of a double value. */
static double sqrt(double a) {
    ...
}

/**
 * Constructs a new String by converting the specified array of
 * bytes using the platform's default character encoding.
 */
public String(byte[] bytes) {
    ...
}

對(duì)于像setFoo()這樣普通的get與set方法就不需要寫Javadoc了砌创,能寫的也不過是“獲取 Foo”。如果方法執(zhí)行了一些復(fù)雜的操作(如強(qiáng)制約束條件或有重要的函數(shù)副作用)鲫懒,那么就需要注釋嫩实。如果讀者不清楚“Foo”屬性具體內(nèi)容時(shí),也需要注釋窥岩。
你寫的每個(gè)方法甲献,無論是公共的還是其他的,都將從Javadoc中受益颂翼。公共方法是API的一部分晃洒,因此需要Javadoc。Android目前沒有強(qiáng)制執(zhí)行一個(gè)特定的風(fēng)格來編寫Javadoc注釋朦乏,但你可以參照這個(gè)說明:如何為Javadoc工具編寫文檔注釋锥累。

短小精煉的方法

盡可能地保持方法的短小精煉。但有時(shí)方法內(nèi)容長又是恰當(dāng)?shù)募圆⒉挥残韵拗品椒ǖ膬?nèi)容長度桶略。如果一個(gè)方法超過40行左右,可以考慮在不破壞程序結(jié)構(gòu)的前提下對(duì)其拆解。

固定位置中定義字段

在文件的頂部或在使用它們的方法之前定義字段际歼。

限制變量范圍

將局部變量的范圍保持為最小惶翻。通過這樣做,我們可以提高代碼的可讀性和可維護(hù)性鹅心,并減少出錯(cuò)的可能性吕粗。每個(gè)變量應(yīng)該在包含變量的所有使用的最內(nèi)部塊中聲明。
局部變量應(yīng)該在它們第一次使用的點(diǎn)被聲明旭愧。幾乎每個(gè)局部變量聲明都應(yīng)該包含一個(gè)初始化器颅筋。在你還沒有足夠的初始化條件時(shí)就不要聲明局部變量,推遲到條件充足時(shí)是更為明智的選擇输枯。
在try-catch語句塊中议泵,如果變量通過一個(gè)會(huì)拋出異常的方法的返回值來初始化,則必須在try塊中進(jìn)行桃熄。如果值必須在try塊之外使用先口,那么它就得在try塊之前聲明,此時(shí)還不能明確地初始化:

// Instantiate class cl, which represents some sort of Set
Set s = null;
try {
    s = (Set) cl.newInstance();
} catch(IllegalAccessException e) {
    throw new IllegalArgumentException(cl + " not accessible");
} catch(InstantiationException e) {
    throw new IllegalArgumentException(cl + " not instantiable");
}

// Exercise the set
s.addAll(Arrays.asList(args));

然而瞳收,即使這種情況也可以通過在一個(gè)方法中封裝try-catch塊來避免:

Set createSet(Class cl) {
    // Instantiate class cl, which represents some sort of Set
    try {
        return (Set) cl.newInstance();
    } catch(IllegalAccessException e) {
        throw new IllegalArgumentException(cl + " not accessible");
    } catch(InstantiationException e) {
        throw new IllegalArgumentException(cl + " not instantiable");
    }
}

...

// Exercise the set
Set s = createSet(cl);
s.addAll(Arrays.asList(args));

若不是有逼不得已的原因碉京,循環(huán)變量應(yīng)該在for語句體內(nèi)聲明:

for (int i = 0; i < n; i++) {
    doSomething(i);
}

以及

for (Iterator i = c.iterator(); i.hasNext(); ) {
    doSomethingElse(i.next());
}

排序?qū)胝Z句

import語句的順序:

  1. Android包
  2. 第三方包(comjunit螟深、net谐宙、org
  3. javajavax

要完全匹配IDE設(shè)置,導(dǎo)入順序應(yīng)為:

  • 每個(gè)分組中按字母順序排列界弧,大寫字母在小寫之前(如:Z在a之前)
  • 在每個(gè)主要分組(android卧惜、comjunit夹纫、netorg设凹、java舰讹、javax)之間用空行分隔。

最初闪朱,對(duì)排序沒有樣式要求月匣,這意味著IDE可能會(huì)經(jīng)常改變順序,或者開發(fā)人員須禁用自動(dòng)導(dǎo)入來進(jìn)行手動(dòng)維護(hù)導(dǎo)入奋姿。這很糟糕锄开。當(dāng)Java風(fēng)格提出時(shí),首選樣式經(jīng)過一段多變而有混亂的過程之后歸結(jié)為簡單地“選擇一個(gè)兼容的排序方案”称诗。所以我們選擇了一種風(fēng)格萍悴,更新了風(fēng)格指南,并讓IDE遵守它。以后IDE將按照此方案自行維護(hù)包的導(dǎo)入癣诱,而我們則無需再做額外操作计维。
風(fēng)格是這樣選取的:

  • 想最先看到的導(dǎo)入應(yīng)放置于頂部(android)。
  • 最不想看到的導(dǎo)入應(yīng)放置于底部(java)撕予。
  • 大家更易于遵循的風(fēng)格鲫惶。
  • IDE可以遵循的風(fēng)格。

靜態(tài)導(dǎo)入的使用及位置仍存在一些爭議实抡。有些人傾向于靜態(tài)導(dǎo)入穿插在其他導(dǎo)入之間欠母,而有些人則更樂意靜態(tài)導(dǎo)入在所有導(dǎo)入頂部或底部。加之吆寨,我們也沒有確定如何使所有IDE使用相同的順序赏淌。由于許多人認(rèn)為這是個(gè)低優(yōu)先級(jí)的問題,所以保持兼容性的前提下自行判斷即可鸟废。

空格縮進(jìn)

使用4個(gè)空格而非制表符進(jìn)行塊縮進(jìn)猜敢。存在疑問時(shí),保持與周圍代碼一致即可盒延。
使用8個(gè)空格進(jìn)行自動(dòng)換行缩擂,包括函數(shù)調(diào)用及賦值運(yùn)算。正確示例:

Instrument i =
        someLongExpression(that, wouldNotFit, on, one, line);

錯(cuò)誤示例:

Instrument i =
    someLongExpression(that, wouldNotFit, on, one, line);

遵循字段命名規(guī)則

  • 非公共添寺,非靜態(tài)字段名以m開頭胯盯。
  • 靜態(tài)字段名稱以s開頭。
  • 其他字段以小寫字母開頭计露。
  • 公共靜態(tài)final字段(常量)為ALL_CAPS_WITH_UNDERSCORES博脑。

示例:

public class MyClass {
    public static final int SOME_CONSTANT = 42;
    public int publicField;
    private static MyClass sSingleton;
    int mPackagePrivate;
    private int mPrivate;
    protected int mProtected;
}

使用標(biāo)準(zhǔn)括號(hào)風(fēng)格

左大括號(hào)不要獨(dú)立成行; 與其之前的代碼在同一行:

class MyClass {
    int func() {
        if (something) {
            // ...
        } else if (somethingElse) {
            // ...
        } else {
            // ...
        }
    }
}

我們需要在條件語句周圍添加括號(hào)。例外:如果整個(gè)條件(條件和主體)適合一行票罐,你可以(非必須)把它全部放在一行上叉趣。 例如,這是可行的:

if (condition) {
    body();
}

這也是可行的:

if (condition) body();

但這是不好的:

if (condition)
    body();  // bad!

列長限制

代碼中的每行文字長度最多為100個(gè)字符该押。雖然關(guān)于這個(gè)規(guī)則存在很多爭論疗杉,但最終決定仍舊是100個(gè)字符。以下例外:

  • 如果注釋行包含示例命令或長度超過100個(gè)字符的URL文本蚕礼,則該行可能長于100個(gè)字符烟具,以便于剪切和粘貼。
  • 導(dǎo)入行可以超過限制奠蹬,因?yàn)槿藗兒苌倏吹剿鼈儯ㄟ@也簡化了工具寫入)朝聋。

使用標(biāo)準(zhǔn)Java注解

注解應(yīng)位于同一語句元素的其他修飾符之前。簡單的標(biāo)記注解(如@Override)可以與語句元素列在同一行囤躁。如果有多個(gè)注解或參數(shù)化注解冀痕,它們則應(yīng)按字母順序逐行列出荔睹。
Java中三種預(yù)定義注解的Android標(biāo)準(zhǔn)用法是:

  • @Deprecated:不再鼓勵(lì)使用的過時(shí)的語句元素必須使用@Deprecated注解。如果使用@Deprecated注解金度,則還必須具有Javadoc的@deprecated標(biāo)記应媚,并且指出替代方案。此外猜极,請記住中姜,@Deprecated方法仍然應(yīng)該工作。 如果您看到舊代碼帶有@deprecated Javadoc標(biāo)記跟伏,請?zhí)砑覢Deprecated注釋丢胚。
  • @Override:只要方法從超類覆蓋聲明或?qū)崿F(xiàn),就必須使用@Override注解受扳。例如携龟,如果使用Javadoc的@inheritdocs標(biāo)記,并從類(而不是接口)派生勘高,則還必須@Overrides注解該方法峡蟋,表明其覆蓋父類的方法。
  • @SuppressWarnings:在無法消除警告的情況下才可以使用@SuppressWarnings注解华望。如果警告通過了“不可消除”測試蕊蝗,則必須使用@SuppressWarnings注解,以確保所有警告都反映代碼存在實(shí)際問題赖舟。
    當(dāng)需要使用@SuppressWarnings注解時(shí)蓬戚,就必須以TODO注釋出為何出現(xiàn)“不可消除”的情形。通常會(huì)定義出是哪個(gè)類提供了一個(gè)糟糕的接口宾抓。例如:
   // TODO: The third-party class com.third.useful.Utility.rotate() needs generics
   @SuppressWarnings("generic-cast")
   List<String> blix = Utility.rotate(blax);
當(dāng)必須使用@SuppressWarnings注解時(shí)子漩,應(yīng)該重構(gòu)代碼以分離出需要使用該注解的語句元素。

運(yùn)用首字母縮略詞

使用首字母縮略詞及簡寫來命名變量石洗、方法和類以提高可讀性:

XmlHttpRequest XMLHTTPRequest
getCustomerId getCustomerID
class Html class HTML
String url String URL
long id long ID

由于JDK和Android代碼庫在首字母縮略詞之間非常不一致幢泼,因此幾乎不可能與周圍的代碼一致。所以讲衫,始終將首字母縮寫作為詞缕棵。

使用TODO注釋

使用TODO來注釋臨時(shí)的、解決方案短暫的或者足夠好但并不完美的代碼焦人。TODO需全大寫后跟冒號(hào):

// TODO: Remove this code after the UrlTable2 has been checked in.

以及

// TODO: Change this to use a flag instead of a constant.

如果您的TODO的形式是“在未來的日期做某事”,請確保您包括一個(gè)非常具體的日期(“在2005年11月修復(fù)”)或一個(gè)非常具體的事件(“在所有產(chǎn)品版本提升到V7之后刪除此代碼”)重父。

謹(jǐn)慎打印

雖然日志是有必要的花椭,但是它對(duì)性能具有顯著的負(fù)面影響,并且隨著日志的長度變大房午,其有效性損失越多矿辽。日志打印器提供了五種不同級(jí)別的日志:

  • ERROR:致命錯(cuò)誤出現(xiàn)時(shí)使用,即導(dǎo)致不可逆的用戶可見效果,像隱式地刪除數(shù)據(jù)袋倔、卸載應(yīng)用程序雕蔽、擦數(shù)數(shù)據(jù)分區(qū)或刷設(shè)備(或更糟)。這個(gè)級(jí)別始終會(huì)被打印出來宾娜。通過ERROR級(jí)別的日志來收集異常并發(fā)送給統(tǒng)計(jì)服務(wù)器是個(gè)不錯(cuò)的方案批狐。
  • WARNING:嚴(yán)重的意外事件發(fā)生時(shí)使用,即導(dǎo)致可恢復(fù)的用戶可見效果前塔,像并不會(huì)導(dǎo)致數(shù)據(jù)丟失的失誤操作嚣艇、一直等待或重啟應(yīng)用、重新下載一個(gè)新版本或重啟設(shè)備华弓。這個(gè)級(jí)別始終會(huì)被打印出來食零。通過WARNING級(jí)別的日志來收集異常并發(fā)送給統(tǒng)計(jì)服務(wù)器也是可以考慮的方案。
  • INFORMATIVE:大多數(shù)人所關(guān)注的重要事件發(fā)生時(shí)使用寂屏,即檢測到一些具備廣泛影響但并不是錯(cuò)誤的情況贰谣。其應(yīng)該由領(lǐng)域中最具權(quán)威性的模塊來打印(以避免非授權(quán)的組件來重復(fù)打印日志)迁霎。這個(gè)級(jí)別始終會(huì)被打印出來吱抚。
  • DEBUG:用于進(jìn)一步打印設(shè)備上可能與調(diào)試意外行為有關(guān)的內(nèi)容。你應(yīng)該只打印你的組件上發(fā)生的那些你所需要收集的足夠信息欧引。如果調(diào)試日志占了你的日志主導(dǎo)频伤,那么你應(yīng)該使用詳細(xì)日志記錄。
    這個(gè)級(jí)別始終會(huì)被打印出來芝此。即使是正式版本憋肖,需要添加條件判斷來禁用所有的調(diào)試日志(如:if (LOCAL_LOG)if (LOCAL_LOGD))婚苹。if的判斷條件最好不要是活動(dòng)邏輯岸更。打印所需的字符串的創(chuàng)建最好也包含在if語句里面。如果打印字符串在if語句外部構(gòu)建膊升,則不應(yīng)在方法調(diào)用中重新映射日志調(diào)用怎炊。
    有些代碼堅(jiān)持使用非標(biāo)準(zhǔn)命名的方案if (localLOGV),其尚可接受廓译。
  • VERBOSE:以外的所有打印都可以使用這個(gè)评肆。只在調(diào)試版本中打印此級(jí)別的日志,并需要if語句包裹非区,才能默認(rèn)被編譯出來瓜挽。if語句中的字符串構(gòu)建將在正式版中刪除。

注意:

  • 在給定的模塊中征绸,除了在VERBOSE級(jí)別久橙,如果可以俄占,一個(gè)錯(cuò)誤只應(yīng)報(bào)告一次。在模塊內(nèi)的單個(gè)函數(shù)調(diào)用鏈中淆衷,只有最內(nèi)層函數(shù)應(yīng)該返回錯(cuò)誤缸榄,如果明顯有助于隔離問題,那么同一模塊中的調(diào)用者應(yīng)該只添加一些日志祝拯。
  • 在一個(gè)模塊鏈當(dāng)中甚带,除VERBOSE級(jí)別,當(dāng)?shù)图?jí)模塊檢測到來自高級(jí)模塊的無效數(shù)據(jù)時(shí)鹿驼,低級(jí)模塊只應(yīng)將此情況記錄到DEBUG日志中欲低,并且僅當(dāng)日志提供的信息對(duì)調(diào)用者來說不可用。具體來說畜晰,不需要打印拋出異常的位置(異常應(yīng)包含所有相關(guān)信息)砾莱,或者日志的所有信息包含在錯(cuò)誤代碼中。這在框架和應(yīng)用程序之間的交互中尤其重要凄鼻,由框架處理的第三方應(yīng)用引起的情形腊瑟,所觸發(fā)的日志級(jí)別不應(yīng)高于DEBUG級(jí)別。只有當(dāng)模塊或應(yīng)用程序檢測到來自其自身級(jí)別或較低級(jí)別的錯(cuò)誤時(shí)块蚌,才能觸發(fā)INFORMATIVE或更高級(jí)別的日志打印闰非。
  • 有些日志打印會(huì)多次用到相同(或非常相似)的數(shù)據(jù)時(shí),可以提取公共數(shù)據(jù)用于打印日志峭范,以便更好地節(jié)約資源财松。
  • 網(wǎng)絡(luò)連接的丟失完全是常見而又預(yù)期內(nèi)的,不應(yīng)該打印日志纱控。網(wǎng)絡(luò)連接丟失的日志應(yīng)該為DEBUG或VERBOSE級(jí)別(在正式版中是否打印日志取決于后果與非預(yù)期的嚴(yán)重程度)辆毡。
  • 在第三方應(yīng)用程序提供的文件系統(tǒng)中具備一個(gè)完整的文件系統(tǒng)的,不應(yīng)打印級(jí)別高于INFORMATIVE的日志甜害。
  • 來自任何不受信任的源(包括共享存儲(chǔ)上的任何文件舶掖,或通過任何網(wǎng)絡(luò)獲取的數(shù)據(jù))的無效數(shù)據(jù)被視為預(yù)期的,并且當(dāng)檢測數(shù)據(jù)無效時(shí)尔店,不應(yīng)觸發(fā)高于DEBUG的級(jí)別的日志打诱H痢(甚至對(duì)高級(jí)別的日志打印也應(yīng)受限制)。
  • 記住嚣州,對(duì)字符串使用+運(yùn)算符時(shí)鲫售,會(huì)隱式創(chuàng)建一個(gè)帶有緩沖區(qū)(16字符)及其他臨時(shí)String對(duì)象的StringBuilder。顯式地創(chuàng)建StringBuilder并不比直接使用“+”更耗費(fèi)資源(實(shí)際上更高效)该肴。記住情竹,即便日志并不會(huì)被用于閱讀,在正式版中Log.v()方法照樣會(huì)被編譯執(zhí)行沙庐,包括打印的字符串鲤妥。
  • 所有高于DEBUG級(jí)別的日志,用于給他人閱讀或在正式版也啟用拱雏,則必須簡潔且易于理解棉安。
  • 必要的時(shí)候,如果可能铸抑,記錄應(yīng)該保持在一行贡耽。線長度最多可達(dá)80或100個(gè)字符是完全可以接受的,如果可能鹊汛,應(yīng)避免長度大于130或160個(gè)字符(包括標(biāo)簽的長度)蒲赂。
  • 不應(yīng)使用高于VERBOSE的級(jí)別記錄報(bào)告成功的日志。
  • 用于追蹤難以重現(xiàn)的問題的臨時(shí)日志應(yīng)當(dāng)使用DEBUG或者VERBOSE級(jí)別刁憋,并且包裹在if語句中滥嘴,以便完成問題追蹤后完全禁用它。
  • 小心日志中的安全漏洞至耻。避免打印私人信息若皱。毫無疑問地,也應(yīng)避免打印保護(hù)的內(nèi)容尘颓。這在編寫框架代碼時(shí)尤其重要走触,因?yàn)槭孪炔蝗菀字朗裁词撬饺诵畔⒒蚴鼙Wo(hù)的內(nèi)容。
  • 禁用System.out.println()(或native的printf())疤苹。System.out和System.err被重定向到/dev/null互广,所以你的打印語句將沒有可見的效果。然而卧土,對(duì)于這些打印所需要的字符串仍然被構(gòu)建了惫皱。
  • 日志的黃金規(guī)則:你的日志不必要的情況下不會(huì)將其他日志推出緩沖區(qū),其他日志也不會(huì)對(duì)你的日志這么做夸溶。

風(fēng)格一致

我們一致認(rèn)為:保持代碼風(fēng)格一致逸吵。如果您正在編輯代碼,請花幾分鐘時(shí)間查看周圍的代碼并確定其樣式缝裁。如果代碼在if條件左右使用了空格扫皱,那么你也該這么做。如果代碼的注釋用星星框起來捷绑,那么你也保證你的注釋用星星框起來韩脑。
編碼風(fēng)格指導(dǎo)的要點(diǎn)是有一個(gè)通用的編碼詞匯,所以人們可以專注于你在說什么粹污,而不是你如何說段多。我們在這里提出全球化的風(fēng)格規(guī)則,所以人們知道編碼詞匯壮吩,但本土化的風(fēng)格也很重要进苍。如果你添加到一個(gè)文件的代碼看起來與現(xiàn)有的代碼有很大的不同加缘,當(dāng)讀者閱讀它時(shí),它會(huì)使讀者脫離他們的節(jié)奏觉啊。所有盡量避免這一點(diǎn)拣宏。

Javatests風(fēng)格規(guī)則


遵循測試方法命名規(guī)則,使用下劃線將要測試的內(nèi)容與要測試的特定案例分開杠人。這種風(fēng)格讓閱讀者更容易看懂正在被測試的案例勋乾。例如:

testMethod_specificCase1 testMethod_specificCase2

void testIsDistinguishable_protanopia() {
    ColorMatcher colorMatcher = new ColorMatcher(PROTANOPIA)
    assertFalse(colorMatcher.isDistinguishable(Color.RED, Color.BLACK))
    assertTrue(colorMatcher.isDistinguishable(Color.X, Color.Y))
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市嗡善,隨后出現(xiàn)的幾起案子辑莫,更是在濱河造成了極大的恐慌,老刑警劉巖罩引,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件各吨,死亡現(xiàn)場離奇詭異,居然都是意外死亡袁铐,警方通過查閱死者的電腦和手機(jī)绅你,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來昭躺,“玉大人忌锯,你說我怎么就攤上這事×祆牛” “怎么了偶垮?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長帝洪。 經(jīng)常有香客問我似舵,道長,這世上最難降的妖魔是什么葱峡? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任砚哗,我火速辦了婚禮,結(jié)果婚禮上砰奕,老公的妹妹穿的比我還像新娘蛛芥。我一直安慰自己,他們只是感情好军援,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布仅淑。 她就那樣靜靜地躺著,像睡著了一般胸哥。 火紅的嫁衣襯著肌膚如雪涯竟。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音庐船,去河邊找鬼烹困。 笑死躲胳,一個(gè)胖子當(dāng)著我的面吹牛勋陪,可吹牛的內(nèi)容都是我干的秉继。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼盗棵,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了北发?” 一聲冷哼從身側(cè)響起纹因,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎琳拨,沒想到半個(gè)月后瞭恰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡狱庇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年惊畏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片密任。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡颜启,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出浪讳,到底是詐尸還是另有隱情缰盏,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布淹遵,位于F島的核電站口猜,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏透揣。R本人自食惡果不足惜济炎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望辐真。 院中可真熱鬧须尚,春花似錦、人聲如沸侍咱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽放坏。三九已至咙咽,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間淤年,已是汗流浹背钧敞。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來泰國打工蜡豹, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人溉苛。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓镜廉,卻偏偏與公主長得像,于是被迫代替她去往敵國和親愚战。 傳聞我的和親對(duì)象是個(gè)殘疾皇子娇唯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,810評(píng)論 6 342
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,111評(píng)論 25 707
  • 【讀經(jīng)】 箴言30 【金句】 神的言語句句都是煉凈的;投靠他的寂玲,他便作他們的盾牌塔插。(箴言 30:5 和合本) 【感...
    chanor閱讀 548評(píng)論 0 0
  • 我們?nèi)绾稳ピO(shè)計(jì)一個(gè)簡單的log系統(tǒng)呢,在看著個(gè)項(xiàng)目之前還真是沒有好好的想過拓哟,當(dāng)然也不是說這個(gè)項(xiàng)目有多么多么屌想许,它也...
    阿瑟李閱讀 2,524評(píng)論 1 5
  • 我是一個(gè)很逗比的程序猿,也是想來試試水断序,想寫寫不一樣的博文流纹。 說起端口,最近的項(xiàng)目才加入了這個(gè)門派违诗。大家都覺得...
    奔跑的達(dá)達(dá)閱讀 432評(píng)論 1 2