有很多爲Android開源社區貢獻代碼的程序員,每個人都有不同的代碼風格,爲此google出了官方的代碼規範,供貢獻者的參考。本文爲其中文翻譯。
下面的這些既不是指導也不是建議,而是實實在在嚴格的規則,Android開源社區貢獻者的代碼如果不遵守這些規則,將不會被收錄。
並不是所有的代碼都遵循下面的規則,但是希望新書寫的代碼都如此。
1、不要忽略對異常的處理
有些時候,代碼似乎忽略了對異常的處理:
void setServerPort(String value) {
try {
serverPort = Integer.parseInt(value);
} catch (NumberFormatException e) { }
}
儘管你認爲你的代碼用於不會遇到拋出異常的錯誤或者對其處理並不重要,但是請千萬別這麼做。忽略對異常的處理,就好像在哪一天會被別人瀏覽的代碼裏埋下了地雷。你必須對每個異常根據具體的情況做出原則上的處理。
Java語言的聯合創始人James Gosling曾經說過,任何時候哪個人寫了對異常空處理的程序,都應該感到不寒而慄。而在這個時候,恰恰需要我們做出正確的事,至少你也應該考慮過。在Java中,程序員永遠不能逃離不寒而慄的感覺。
可供接受的選擇如下所示:
- 在調用函數後面加上異常判斷:
-
void setServerPort(String value) throws NumberFormatException { serverPort = Integer.parseInt(value); }
- 在異常處理中拋出已在函數後面加上的異常
-
void setServerPort(String value) throws ConfigurationException { try { serverPort = Integer.parseInt(value); } catch (NumberFormatException e) { throw new ConfigurationException("Port " + value + " is not valid."); } }
- 優雅的處理異常,重新賦值
-
/** 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 } }
- 拋出運行時異常,這是一個非常危險的操作,除非你確認唯一正確合適的事就是崩潰程序。
/** 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);
}
}
需要記錄好異常以及傳遞給了運行時異常的構造方法,如果您必須在Java1.3版本下編譯,舊的異常將被拋棄
- 如果您實在不需要處理,您也需要在此處加上說明
-
/** 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. } }
2、不要抓取通用的異常
有些時候,一些懶惰的程序員像如下的格式抓取異常:
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!
}
你不應該這樣做。在所有的案例中,抓卻通用的異常和錯誤超類都是不合適的,尤其是錯誤超類,因爲錯誤超類還包括了錯誤Error,這是十分危險的舉動。這意味着你不能將一些你永遠都不回預期的異常,包括運行時的異常當做普通應用級別的錯誤處理。它掩蓋了合理處理代碼不會發生的錯誤。即使某人加入了新的自定義異常,編譯器也不會提醒你區處理。所以在所有的代碼中,你都不應該把所以的異常都統一用通用的異常處理。
3、不要自己使用Java的Finalizer回收資源
我們不推薦使用Java的finalize()方法,你能得到在異常中你需要在Finalizer中執行的處理。即使你絕對需要,也應該使用close()方法或者類似的方法,當Finalizer的方法被調用時。
4、完整的導入名
推薦使用完成的導入名,比如import foo.*是沒有import foo.Bar好的。
5、在代碼前加上標準的說明
每個文件都應該在頂部有個標準的說明
/*
* 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 {
...
}
每個類或者方法前也需要加上相應的說明:
比如:
/** 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) {
...
}
7、編寫儘量短小的方法
爲了代碼的變通性,儘量讓方法短小用途專一。考慮到有的方法的長度確實很長,所以對方法的長度並沒有硬性的標準。當方法的長度達到40行時,請考慮下是否可以優化。
8、Field定義在標準的位置
Field定義在文件頂部,或者需要使用它的方法前面。
9、限制變量的作用域
變量的作用域應控制在最小的範圍,只有這樣,才能提高代碼的可讀性、可維護性減少相似的錯誤。
10、給導入的包排列
- Android的包
- 第三方的包
- java和javax
11、使用空格縮行
使用4個空格代替Tab,在不同的編譯環境中,Tab所表示的長度不一致。
12、符合命名規則
- 非public和非static的變量名以m開頭
- static變量以s開頭
- 其他變量的開頭爲小寫的單詞
- public和static的變量全部大寫
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;
}
13、正確使用大括號
左大括號緊跟代碼,不另起一行。
class MyClass {
int func() {
if (something) {
// ...
} else if (somethingElse) {
// ...
} else {
// ...
}
}
}
14、空值行的長度
行的長度控制在100個單詞以內。
15、使用正確的Java註解(Annotations)
在修飾符之前使用。有些簡單的標記型的註解,能夠和代碼保持在一行。如果有多條註解,每條註解佔用一行,
@Deprecated
: 當方法不在被推薦使用時,將使用此註解。@Override
: 當重寫父類的方法時,使用此註解@SuppressWarnings
: 批註允許您選擇性地取消特定代碼段(即,類或方法)中的警告。其中的想法是當您看到警告時,您將調查它,如果您確定它不是問題,您就可以添加一個 @SuppressWarnings 批註,以使您不會再看到警告。雖然它聽起來似乎會屏蔽潛在的錯誤,但實際上它將提高代碼安全性,因爲它將防止您對警告無動於衷 — 您看到的每一個警告都將值得注意。
16、縮寫或省略按正常變量命名
17、使用To do的註釋
18、節約使用Log
當使用Log的時候,對App的表現有負面的影響,同時也會降低簡潔性。
19、代碼風格連貫性
如果您正在修改代碼,建議花幾分鐘時間瀏覽下週圍的代碼並熟悉下編碼風格。在您的代碼中,做到一致。
20、測試方法命名
在測試的方法中命名體現出測試了什麼方面的內容。
比如:
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))
}