在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Android/ 關(guān)于代碼風(fēng)格的指導(dǎo)
下載源碼
根據(jù)設(shè)備構(gòu)建
Git 資源
構(gòu)建系統(tǒng)
Android 平臺(tái) 64 位構(gòu)建指導(dǎo)
初始化編譯環(huán)境
Android 源代碼
品牌指南
已知的問題
Repo 命令手冊
構(gòu)建內(nèi)核
Bug 的生命周期
代碼主線、分支和版本
使用 Eclipse
提交補(bǔ)丁
下載與構(gòu)建
參與
項(xiàng)目角色
補(bǔ)丁的生命周期
提交 Bugs
關(guān)于代碼風(fēng)格的指導(dǎo)
開發(fā)
代碼名稱,標(biāo)簽和版本號(hào)

關(guān)于代碼風(fēng)格的指導(dǎo)

以下的規(guī)則并不是普通的指導(dǎo)方針或者我們的推薦,而是嚴(yán)格的規(guī)范。不遵循這些風(fēng)格而構(gòu)建出來的 Android 軟件將不會(huì)被接受。

目前,并不是所有的代碼都符合規(guī)范,但是以后的代碼應(yīng)該向規(guī)范靠攏。

Java 語法規(guī)則

我們遵循標(biāo)準(zhǔn)的 Java 編碼規(guī)范,此外我們加入了一些新的規(guī)范

不能忽視異常

有時(shí)候,開發(fā)者會(huì)傾向于編寫完全忽視了異常的代碼,就像下面這樣:

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

開發(fā)者絕不能像這樣。當(dāng)你覺得你的代碼不會(huì)出現(xiàn)這個(gè)錯(cuò)誤,或者處理這個(gè)錯(cuò)誤并不重要的時(shí)候,像上面的代碼那樣忽略了異常處理就相當(dāng)于在你的代碼中給以后接手的開發(fā)者埋下了地雷,他們總有一天會(huì)在這里遇到問題。你必須將代碼中所有的異常用一種規(guī)范化的方式處理好,具體的處理方式取決于情況的不同。

不管什么時(shí)候,如果代碼中存在空的捕獲語句,開發(fā)者應(yīng)當(dāng)感到毛骨悚然。不論如何,在捕獲語句中,必然存在應(yīng)當(dāng)執(zhí)行的操作,至少你應(yīng)該多考慮一下。在 Java 中,這種恐慌感是無法逃避的。 -James Gosling

可接受的處理方式(可以參照個(gè)人的喜好選擇)有:

  • 由方法的調(diào)用者拋出異常
void setServerPort(String value) throws NumberFormatException {
    serverPort = Integer.parseInt(value);
}
  • 拋出一個(gè)適合你當(dāng)前抽象層次的新異常
void setServerPort(String value) throws ConfigurationException {
    try {
        serverPort = Integer.parseInt(value);
    } catch (NumberFormatException e) {
        throws new ConfigurationException("Port " + value + " is not valid.");
    }
  • 通過在 catch 代碼塊中使用一個(gè)合適的值替代異常值來處理異常
/** 設(shè)置端口號(hào),當(dāng) value 是一個(gè)無效數(shù)字時(shí), 使用 80 替代 */
void setServerPort(String value) {
    try {
        serverPort = Integer.parseInt(value);
    } catch (NumberFormatException e) {
        serverPort = 80; // 服務(wù)器的默認(rèn)端口
    }
}
  • 捕獲異常并拋出一個(gè)新的運(yùn)行時(shí)異常。這種方式存在風(fēng)險(xiǎn):只有當(dāng)你確認(rèn)出現(xiàn)這種錯(cuò)誤的時(shí),令程序崩潰是最合適的處理方式,才能采用該方式。
/** 設(shè)置端口號(hào),如果 value 是一個(gè)無效值,程序中斷。 */
void setServerPort(String value) {
    try {
        serverPort = Integer.parseInt(value);
    } catch (NumberFormatException e) {
        throws new RuntimeException("port " + value + " is invalid, ", e);
    }
}

請注意,原來的異常傳遞給了 RuntimeException 的構(gòu)造器。如果你的代碼必須在 Java 1.3 以下版本編譯,你需要省略掉異常發(fā)生的原因。

  • 最后一招:如果你認(rèn)為忽略屌異常處理是最合適的,并且對此相當(dāng)有信心,那么你可以忽略異常。但是你必須在注釋中說明為什么:
/** 如果 value 是無效的數(shù)字,將會(huì)使用原來的端口號(hào)。 */
void setServerPort(String value) {
    try {
        serverPort = Integer.parseInt(value); 
    } catch (NumberFormatException e) {
        // 文檔中會(huì)注明該方法將忽略掉用戶輸入的無效值
        // serverPort 將不會(huì)發(fā)生改變
    }
}

不要捕獲一般性異常(Generic Exception)

有些時(shí)候,為了偷懶,開發(fā)者將會(huì)像下面這樣捕獲異常并作出處理:

try {
    someComplicatedIOFunction();        // 可能拋出 IOException 
    someComplicatedParsingFunction();   // 可能拋出 ParsingException 
    someComplicatedSecurityFunction();  // 可能拋出 SecurityException 
    // phew, made it all the way 
} catch (Exception e) {                 // 我希望捕獲所有的異常
    handleError();                      // 一個(gè)普通的 handler
}

你不能這樣做。幾乎所有情況下都不適合捕獲一般性異常,因?yàn)槠渲邪ㄟ€包括了錯(cuò)誤異常,這是相當(dāng)危險(xiǎn)的。這意味著你并不期待的異常(包括運(yùn)行時(shí)異常,就像 ClassCastException)最后卻在應(yīng)用級(jí)別的錯(cuò)誤處理中被捕獲。它掩蓋了處理失敗的代碼,這意味著如果有人在您正在調(diào)用的代碼中添加了一個(gè)新類型的異常,編譯器無法告訴你需要以不同的方式處理該錯(cuò)誤。并且在幾乎全部情況下,你都不應(yīng)該以同種方式處理不同種類的異常。

這一規(guī)則有極少數(shù)例外:在某些測試代碼和頂級(jí)代碼中,你希望捕捉所有類型的異常(以防止他們在界面中顯示或者繼續(xù)進(jìn)行批處理作業(yè))。在這種情況下,你需要捕獲一般性異常并合適地處理錯(cuò)誤。這么做之前你需要謹(jǐn)慎考慮,然后在注釋中解釋為什么在這里這么做是安全的。

替代捕獲一般性異常的選項(xiàng):

  • 在同一個(gè) try 語句之后設(shè)置多個(gè)分離的 catch 塊來處理不同的異常。這個(gè)方法可能不太方便,但是要比捕獲所有異常要好不少。需要注意的是,catch 塊中應(yīng)盡量避免代碼重復(fù)過多。

  • 通過多個(gè) try 語句重構(gòu)代碼以使錯(cuò)誤處理的粒度更細(xì)小,把 IO 從 parsing 分離出來,在不同的情況中單獨(dú)處理錯(cuò)誤。

  • 重新拋出異常。很多情況下,你不需要在當(dāng)前層次下捕獲異常,此時(shí)只需在方法中拋出異常即可。

記?。寒惓J悄愕呐笥眩‘?dāng)編譯器告訴你還有異常沒有被捕獲的時(shí)候,不要皺眉。此時(shí)應(yīng)該微笑:編譯器令你能夠更加輕松地在自己的代碼中捕獲運(yùn)行時(shí)異常,是值得高興的事。

不要使用終結(jié)器(Finalizers)

終結(jié)器是一種可以在對象被垃圾回收器回收時(shí),執(zhí)行一大塊代碼的方法。

優(yōu)點(diǎn):方便清理,特別是針對外部資源的時(shí)候。

缺點(diǎn):并不能保證終結(jié)器什么時(shí)候會(huì)被調(diào)用,甚至有時(shí)候它根本不會(huì)被調(diào)用。

判定:我們不應(yīng)使用終結(jié)器。在大多數(shù)情況下,你可以在終結(jié)器中執(zhí)行你需要的操作,并且能實(shí)現(xiàn)良好的異常處理。如果你一定需要它,定義一個(gè) close() 方法(或者是 like)并注明什么時(shí)候它應(yīng)該被調(diào)用。我們可以把 InputStream 當(dāng)做一個(gè)例子來說明一下。在這種情況下,它并不是一定要在終結(jié)器中輸出日志信息,但是,如果并不希望輸出太多日志信息的話,在終結(jié)器中輸出小段日志信息是很合適的方法。

完全限定引用

當(dāng)你希望使用 foo 包中的 Bar 類的時(shí)候,你又兩種方法實(shí)現(xiàn):

  1. import foo.*;
  2. import foo.Bar;

第一種方式優(yōu)點(diǎn):可能會(huì)減少 import 語句的數(shù)量。 第二種方式優(yōu)點(diǎn):把要使用的類描述出來了,使得代碼在維護(hù)時(shí)更具可讀性。

判定:引用Android 代碼的時(shí)候使用第二種形式。Java 標(biāo)準(zhǔn)庫(java.util.*, java.io.*等)和單元測試代碼(junit.framework.*)是例外。

Java 資源庫規(guī)范

使用Android 中的 Java 庫和工具會(huì)帶來許多便利。有些情況下,這種便利性在一些重要方面發(fā)生了改變,因?yàn)榕f的代碼可能使用的是已經(jīng)棄用的模式或者資源庫。使用這樣的代碼時(shí),直接使用已有的模式是沒問題的。但是當(dāng)創(chuàng)建新的組件的時(shí)候,不要使用棄用的資源庫。

Java 樣式規(guī)范

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

每個(gè)文件都會(huì)在其頂部放置版權(quán)聲明。然后是包的聲明和引用語句,用空行把不同作用的語句塊分離開來。接下來是類或者接口的聲明。在 Javadoc 標(biāo)準(zhǔn)注釋中,要描述類或者接口的作用。

/*
 * Copyright (C) 2013 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è)類和有價(jià)值的公共方法,你都應(yīng)該為之書寫一個(gè) Javadoc 注釋,該注釋至少包含一句關(guān)于類或方法作用的描述。并且這個(gè)描述應(yī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) 

你并不需要為沒價(jià)值的 get 或者 set 方法書寫 Javadoc,比如,對于 setFoo() 方法,你在 Javadoc 中只能說設(shè)置了 Foo 的值。如果該方法所做的事情更加復(fù)雜(比如強(qiáng)制約束或者有一個(gè)重要的副作用),那你應(yīng)該寫一個(gè) Javadoc。假設(shè)之前的例子中,F(xiàn)oo 這個(gè)屬性的意思并不明確,那就該添加一個(gè) Javadoc。

你所寫的每一個(gè)方法,不論是公有的還是其他的,都將受益于 Javadoc。而公共函數(shù)是 API 的一部分,所以需要 Javadoc。

Android 目前并不強(qiáng)制開發(fā)者使用特定的 Javadoc 書寫風(fēng)格,但是你應(yīng)該遵循 How to Write Doc Comments for the Javadoc Tool 中的規(guī)范。

編寫短小的方法(Short Method)

在可行的范圍內(nèi),方法應(yīng)該盡量向小型化和集中化靠攏。但是,也要認(rèn)識(shí)到,有些情況下較長的方法更加合適,所以對于方法的長度并不做硬性要求。如果某個(gè)方法的代碼超出了40行,那么應(yīng)該考慮一下是否能將它分解為小方法并且不影響到程序的結(jié)構(gòu)。

在標(biāo)準(zhǔn)的地方定義字段

字段應(yīng)該在文件頂部定義,或者在即將使用它們的方法前定義。

限制變量的范圍

局部變量的存在范圍應(yīng)該盡可能地低。這樣做將會(huì)增加代碼的可讀性和可維護(hù)性,并且還能降低出錯(cuò)的可能性。在嵌套的代碼塊中,每個(gè)變量應(yīng)該在能夠包含所有使用該變量的語句的最小的代碼塊中聲明。

局部變量應(yīng)該在第一次被使用時(shí)聲明。幾乎每個(gè)局部變量的聲明都應(yīng)該包括合理的初始化,如果你沒有沒辦法在此處獲得足夠的信息去初始化這個(gè)變量,那么你應(yīng)該將聲明推遲到你獲得足夠信息的地方。

這個(gè)規(guī)則的一個(gè)例外就是 try-catch 語句。如果一個(gè)變量初始化的時(shí)候,其初始值是一個(gè)拋出已檢查異常的方法的返回值,它就必須在 try 語句內(nèi)初始化。如果這個(gè)變量必須在 try 塊之外被使用,那么它就要在 try 塊之外聲明,盡管在那里它并沒有被合理地初始化:

// 實(shí)例化類 cl,表示某種集合
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");
}

// 運(yùn)用這個(gè)集合
s.addAll(Arrays.asList(args));

但即使是這種情況也能通過把 try-catch 語句封裝在一個(gè)方法中來避免:

Set createSet(Class cl) {
    // 實(shí)例化的類cl,表示某種集合
    try {
        return (Set) cl.newInstance();
    } catch(IllegalAccessException e) {
        throw new IllegalArgumentException(cl + " not accessible");
    } catch(InstantiationException e) {
        throw new IllegalArgumentException(cl + " not instantiable");
    }
}

...

// 運(yùn)用這個(gè)集合
Set s = createSet(cl);
s.addAll(Arrays.asList(args));

對于循環(huán)變量,除非有令人信服的理由,否則應(yīng)該在 for 語句中聲明:

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

其他類型的循環(huán)變量:

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

有序的引用語句

引用語句的順序如下:

  1. Android 的引用
  2. 第三方的引用
  3. java 和 javax 的引用

為了更好地符合 IDE 的設(shè)置,這些引用語句應(yīng)該是這樣的:

  • 每個(gè)分組按字母排序,其中大寫字母放在小寫字母前。(比如,Z 在 a 前面)
  • 每個(gè)主要的組之間應(yīng)該用空行隔開(android, com, junit, net, org, java, javax)

最初在順序的風(fēng)格上并沒有要求。也就是說 IDE 總是在改變這些順序,或者說使用 IDE 的開發(fā)人員不得不禁用自動(dòng)引用的特性然后手動(dòng)維護(hù)這些引用語句,這是相當(dāng)不好的。當(dāng)問及 Java 風(fēng)格的時(shí)候,開發(fā)者們喜歡的風(fēng)格是五花八門的。這和我們對于“盡量有序并且一致”的需求完全不同,所以我們選擇了一種風(fēng)格,更新了風(fēng)格指南,并且讓 IDE 來遵循它。我們希望,隨著用戶不斷使用 IDE 來編碼,最終所有的引用語句都能符合這種風(fēng)格。

這種風(fēng)格是這樣的:

  • 人們希望并且往往放在頂部的引用語句(android)
  • 人們希望并且往往放在底部的引用語句(java)
  • 人們要使用這種風(fēng)格很簡單
  • IDE 能夠遵循這種風(fēng)格

靜態(tài)引用的使用和位置一直都存在爭議。有的人喜歡把靜態(tài)引用分散在已有的引用語句中,有些人則希望把它們放在其他所有引用語句的上方或者下方。此外,我們目前也沒有得出一種能夠讓所有 IDE 都遵循統(tǒng)一順序的方法。

由于多數(shù)人認(rèn)為這件事并不重要,所以你需要自行判斷,并盡可能保持一致。

使用空格來縮進(jìn)

我們使用 4 個(gè)空格來縮進(jìn),而不是使用 tab 鍵。對此感到困惑的話,請和你周圍的代碼保持一致。

語句換行的時(shí)候我們使用 8 個(gè)空格來縮進(jìn),包括方法的調(diào)用和賦值語句。例如,這樣是正確的:

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

下面這樣則是不正確的:

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

遵循字段命名慣例

  • 非公有且非靜態(tài)的字段以 m 開頭
  • 靜態(tài)字段以 s 開頭
  • 其他字段以小寫字母開頭
  • 公有的靜態(tài)字段全部大寫并用下劃線連接

例子如下:

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ú)占一行,應(yīng)該放在和前面代碼同一行的位置。就像下面這樣:

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

我們需要在一個(gè)條件語句中使用括號(hào)。只有整個(gè)條件語句中只有一行代碼,你才可以把他放在一行而不使用括號(hào)。就如下面這樣是合法的:

if (condition) {
    body(); 
}

而這樣也是可行的:

if (condition) body();

不過,那這樣也是可以的:

if (condition)
    body();  // 不推薦這樣的風(fēng)格

控制行的長度

你代碼的每一行的長度應(yīng)該限制在 100 個(gè)字符以內(nèi)。

為此我們做了很多討論,最終決定,一行的長度應(yīng)該限制在 100 個(gè)字符以內(nèi)。

例外1:如果一個(gè)注釋語句含有一個(gè)超過 100 個(gè)字符的簡單命令或者是一個(gè) URL,那么為了方便剪切和粘貼,你可以不在意行的長度。

例外2:引用語句可以不管這個(gè)限制,因?yàn)槿藗兒苌僭谝馑麄?。這樣也能簡化工具的編寫。

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

標(biāo)注應(yīng)該先于同一語言元素中的其他修飾符。簡單的標(biāo)注(如 @Override)可以和其他語言元素在同一行中列出。如果有多個(gè)標(biāo)注,或者參數(shù)化的標(biāo)注,他們應(yīng)該各自單獨(dú)占一行并按字母順序排列。

Java 預(yù)定義的三種標(biāo)注在Android 中的標(biāo)準(zhǔn)用法如下:

  • @Deprecated. 當(dāng)被標(biāo)注的元素不鼓勵(lì)使用的時(shí)候你必須使用 @Deprecated 標(biāo)注,你還需要使用 Javadoc 添加 @deprecated 標(biāo)記并且該標(biāo)記應(yīng)該用可選的名字實(shí)現(xiàn)。此外,請記住,@Deprecated 方法依舊是可以執(zhí)行的。
    (對于以前的代碼,如果有一個(gè) Javadoc 的 @deprecated 標(biāo)記,請為代碼加入 @Deprecated 標(biāo)注。
  • @Override. 當(dāng)一個(gè)方法重寫了其父類中的聲明或者實(shí)現(xiàn)的時(shí)候,必須用 @Override 來注明。比如,如果你有一個(gè)方法有 Javadoc 的標(biāo)記 @inheritdocs,并且是從一個(gè)類(不是接口)中派生而來的,你就必須再為方法添加 @Override 說明該方法重寫了父類中的相關(guān)方法。
  • SuppressWarnings:@SuppressWarnings 標(biāo)注應(yīng)該只在無法消除警告的情況下使用。如果一個(gè)警告通過了“無法消除”的測試,那么 @SuppressWarnings 標(biāo)注會(huì)被使用,以確保所有的警告都反映了代碼中的實(shí)際問題。

當(dāng)必須使用 @SuppressWarnings 標(biāo)注的時(shí)候,必須在其之前寫一個(gè) TODO 注釋來說明“無法消除”的情況。這通常會(huì)標(biāo)記出一個(gè)使用了一個(gè)比較尷尬的接口的違規(guī)類。例子如下:

// TODO: The third-party class com.third.useful.Utility.rotate() needs generics 
@SuppressWarnings("generic-cast")
List<String> blix = Utility.rotate(blax);

當(dāng)需要 @SuppressWarnings 標(biāo)注的時(shí)候,應(yīng)該重構(gòu)代碼以隔離標(biāo)注中使用的軟件元素。

熟悉首字母縮略詞

在為變量、方法以及類命名的時(shí)候,最好使用首字母縮略詞。這些名稱將會(huì)更具可讀性:

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

不論 JDK 還是Android 的代碼庫都使用了首字母縮略詞,因而他們是相當(dāng)一致的,因此,想使自己的代碼與他們一致是幾乎不可能的。請咬緊牙關(guān),盡量熟悉首字母縮略詞。

使用 TODO 注釋

為代碼使用 TODO 注釋是暫時(shí),短期的解決方案,或者說是夠用的但是并不完美。

TODO 注釋必須用大寫的 TODO 開頭,后面跟一個(gè)冒號(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 語句是“在未來的某一時(shí)期做什么”的格式,請確保你包含了一個(gè)求具體的日期(2005年11月份)或者一個(gè)特定的事件(在所有產(chǎn)品開發(fā)者了解v7協(xié)議后刪除此代碼)。

謹(jǐn)慎使用 Log

當(dāng)日志記錄是必須的時(shí)候,它對性能有顯著的負(fù)面影響并且如果它不保持一定程度的簡潔性的話,就會(huì)迅速失去其有效性。測試系統(tǒng)提供五種不同級(jí)別的日志記錄:

  • Error:這個(gè)等級(jí)的日志信息應(yīng)該只在出現(xiàn)致命錯(cuò)誤的時(shí)候使用,比如,有些事件會(huì)導(dǎo)致用戶可見的結(jié)果并且如果不顯示地刪除數(shù)據(jù),卸載應(yīng)用,清理數(shù)據(jù)分區(qū)或者重新刷掉整個(gè)手機(jī)(可能更糟)的時(shí)候就無法修正該結(jié)果,這個(gè)級(jí)別的信息會(huì)一直記錄下來。在向統(tǒng)計(jì)數(shù)據(jù)的服務(wù)器提交報(bào)告的時(shí)候,說明 ERROR 級(jí)別的日志中的情況通常是一種好的選擇。
  • Warning:這個(gè)等級(jí)的日志信息應(yīng)該在事情比較嚴(yán)重或者出現(xiàn)預(yù)期之外的結(jié)果時(shí)使用,比如,有些事件會(huì)導(dǎo)致用戶可見的結(jié)果,但是通過一些顯示的動(dòng)作,就像是等待或重啟應(yīng)用程序的應(yīng)用甚至于下載新版的應(yīng)用程序或者重新啟動(dòng)設(shè)備,可以在不丟失數(shù)據(jù)的情況下恢復(fù)。這個(gè)級(jí)別的信息會(huì)一直記錄下來。在向統(tǒng)計(jì)信息的服務(wù)器報(bào)告的時(shí)候,說明 WARNING 級(jí)別的日志信息也是會(huì)考慮的。
  • INFORMATIVE:這一級(jí)別的日志應(yīng)當(dāng)記錄的是大多數(shù)人會(huì)感興趣的信息。比如,當(dāng)發(fā)現(xiàn)某種情況會(huì)造成廣泛的影響時(shí),盡管它不一定是錯(cuò)誤,也應(yīng)該記錄。這種情況只應(yīng)該由一個(gè)被認(rèn)為在該域中是最具權(quán)威性(避免由非權(quán)威的組件做重復(fù)記錄)的模塊記錄。始終記錄該級(jí)別的日志信息。
  • DEBUG:這一級(jí)別的日志信息應(yīng)該用于進(jìn)一步說明在設(shè)備上發(fā)生了什么和調(diào)查及調(diào)試異常行為相關(guān)的事件。你應(yīng)該只有在需要收集關(guān)于組件的足夠信息的時(shí)候進(jìn)行記錄。如果你的調(diào)試日志是主要的日志信息,那你可能需要使用 verbose 日志記錄。這一級(jí)別的日志應(yīng)當(dāng)記錄,即時(shí)是在發(fā)行版中也應(yīng)當(dāng)用 if(LOCAL_LOG) 或者 if (LOCAL_LOGD) 代碼塊中來包含該日志。而在 LOCAL_LOG[D] 中則定義你的類或者子組件,故而要禁用所有這類記錄是有可能的。在 if(LOCAL_LOG) 塊中不應(yīng)當(dāng)含有執(zhí)行的邏輯,所有為日志而構(gòu)建的字符串也應(yīng)該放在 if(LOCAL_LOG) 塊中。如果日志調(diào)用會(huì)導(dǎo)致字符串的構(gòu)建發(fā)生在 if(LOCAL_LOG) 塊之外,那么不應(yīng)該把日志調(diào)用分散到函數(shù)調(diào)用中。還有些代碼仍然使用 if(localLOGV),這也是可接受的,盡管這個(gè)名稱并不規(guī)范。
  • VERBOSE:這個(gè)級(jí)別的日志用于記錄其他所有的信息,只會(huì)在調(diào)試版本中記錄,并且應(yīng)當(dāng)包含在 if(LOCAL_LOGV) 塊中。故而它可以在默認(rèn)情況下編譯,任何因此構(gòu)建的字符串在應(yīng)當(dāng)在 if(LOCAL_LOGV) 塊中出現(xiàn),并且在發(fā)行版中將會(huì)被剝離出來。

注意:

  • 在給定的模塊中,除了 VERBOSE 級(jí)別以外,一個(gè)錯(cuò)誤應(yīng)該盡可能只報(bào)告一次 :在模塊內(nèi)的函數(shù)調(diào)用鏈,只有最內(nèi)層的函數(shù)應(yīng)當(dāng)返回錯(cuò)誤信息,并且同一模塊內(nèi)的調(diào)用者只應(yīng)添加一些有助于分離問題的日志信息。
  • 在一連串模塊中,除了 VERBOSE 級(jí)別以外,當(dāng)?shù)讓幽K檢測到的無效數(shù)據(jù)來自較高模塊,并且只有在日志提供了調(diào)用者無法使用的信息的時(shí)候,低級(jí)別模塊將記錄這種情況到 DEBUG 日志。具體來說,沒有必要在拋出異常的,或者被記錄的信息被包含在錯(cuò)誤信息中的時(shí)候,記錄當(dāng)時(shí)的情況(異常中應(yīng)該會(huì)包括所有相關(guān)的信息)。這在框架和應(yīng)用的交互間尤為重要,并且由第三方應(yīng)用程序造成的情況能夠由框架合理處理的時(shí)候,不應(yīng)該觸發(fā)高于 DEBUG 級(jí)別的記錄。唯一能觸發(fā) INFORMATIVE 或者更高級(jí)別記錄的情況應(yīng)該是當(dāng)模塊或者應(yīng)用在其本身的自別檢測到錯(cuò)誤,或者錯(cuò)誤來自較低級(jí)別的時(shí)候。
  • 當(dāng)有些日志記錄可能會(huì)發(fā)生多次的時(shí)候,實(shí)施一些限制速率的機(jī)制來防止重復(fù)輸出很多與副本相同(或者很相似)的日志信息是一個(gè)好方法。
  • 失去網(wǎng)絡(luò)連接被一致認(rèn)為且期望是不應(yīng)該無理由記錄的。在 app 內(nèi)失去網(wǎng)絡(luò)連接會(huì)出現(xiàn)的后果應(yīng)當(dāng)在 DEBUG 或者 VERBOSE 級(jí)別記錄(根據(jù)后果是否足夠嚴(yán)重并且超出預(yù)期的情況足夠被記錄在發(fā)行版中)。
  • 在一個(gè)文件系統(tǒng)中,一個(gè)可以使用或者代表第三方的完整文件系統(tǒng)不應(yīng)該輸出高于 INFORMAL 的日志。
  • 來自不信任源的無效數(shù)據(jù)(包括任何共享設(shè)備上的文件,或者通過網(wǎng)絡(luò)連接取得的數(shù)據(jù))被檢測出無效的時(shí)候,我們認(rèn)為且應(yīng)當(dāng)不觸發(fā)任何高于 DEBUG 級(jí)別的日志記錄。(甚至應(yīng)該盡可能地限制日志記錄)
  • 在心中記住,當(dāng)對 String 對象使用+連接符的時(shí)候,會(huì)隱式地創(chuàng)建一個(gè)默認(rèn)大?。?16 個(gè)字符)的 StringBuilder 對象,而且可能會(huì)有其他的臨時(shí) String 對象。比如,顯示創(chuàng)建 StringBuilder 的花銷并不使用默認(rèn)的‘+’操作符要大(而且事實(shí)上更加高效)。也請記住,即時(shí)沒有讀日志信息,調(diào)用 Log.v() 的代碼,包括字符串的構(gòu)建,是會(huì)被編譯并且運(yùn)行在發(fā)行版本中的。
  • 任何用于給其他人看并且在發(fā)行版中也可用的日志,應(yīng)當(dāng)盡可能地簡潔,并且應(yīng)當(dāng)是合理易懂的。這包括到 DEBUG 為止的全部日志。
  • 如果可能的話,有意義的的日志應(yīng)該保持在單行內(nèi)。單行的長度在 80 到 100 個(gè)字符內(nèi)是完全可以被接受的,但是長度在 130 到 160 各字符也是可以接受的(包括標(biāo)簽的長度),只是應(yīng)當(dāng)盡量避免。
  • 報(bào)告成功的日志絕對不能使用高于 VERBOSE 級(jí)別的日志。
  • 臨時(shí)記錄用于診斷一個(gè)很難重現(xiàn)的問題,而且應(yīng)該保持在 DEBUG 或者 VERBOSE 級(jí)別,并且應(yīng)當(dāng)封閉在 if 塊之中以允許其在編譯期間能夠被禁用。
  • 對于在日志中泄露的安全信息要小心。私有信息應(yīng)該盡量避免。受保護(hù)的內(nèi)容是必須避免的。在編寫框架代碼的時(shí)候這是非常重要的,因?yàn)樗⒉粫?huì)預(yù)先知道什么是私有信息或者受保護(hù)的信息。
  • 不要使用 System.out.println()(或者 printf() 原生代碼)。System.outSystem.err 可以重定向到 /dev/null,所以你的打印語句不會(huì)有可見的影響。然而,所有銀這些調(diào)用而構(gòu)建的字符串仍然會(huì)被輸出。
  • 關(guān)于日志的最好的規(guī)則就是,你的日志不會(huì)把其他日志推到緩沖區(qū)中,正如其他日志不會(huì)這樣對你的日志一樣。

保持一致

我們的部分想法:保持一致。如果你在編輯代碼,請花一點(diǎn)時(shí)間去觀察一下周圍人的代碼以確定你的風(fēng)格。如果他們在 if 語句的周圍使用空格,你也應(yīng)該這樣。如果他們的注釋是包含在用星號(hào)構(gòu)成的方塊里,你也要把注釋放在星號(hào)構(gòu)成的方塊里。

需要風(fēng)格指南的關(guān)鍵是有一個(gè)共同的代碼詞匯表,于是人們可以專注于你所說的內(nèi)容,而不是你說話的方式。我們提出了整體的風(fēng)格規(guī)范,所以人們知道這個(gè)專業(yè)詞匯表。但是局部的風(fēng)格也是很重要的,如果你在文件中加入的代碼看起來和周圍代碼明顯不同,那么讀者讀到這里的時(shí)候,這些代碼會(huì)使他們的節(jié)奏被打斷,這應(yīng)當(dāng)盡量避免。

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

遵循測試方法的命名便捷性

當(dāng)為測試方法命名的時(shí)候,你可以使用下劃線從特定的測試情況中分離出要測試的東西。這種風(fēng)格可以更好地看出是在什么情況下進(jìn)行測試。

例如:

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))
}