一篇文章搞定android程式設計規範
說明
命名儘量做到見名知意,採用駝峰標識,禁止使用拼音或者表意不明確的標識(比如bianliang、i、j);
命名無法完全表達作者的意思時,才考慮使用註釋;註釋的目的是幫助讀者理解程式碼,提升程式碼的可讀性;
註釋應該表達“我的程式碼為什麼要這麼做?”,而不是表達“我的程式碼做了什麼?”;
儘量降低方法的圈複雜度,遇到不滿足條件時直接返回;
一個變數只有一個意思;一個方法只做一件事情;業務邏輯的具體實現封裝在model層;要保證程式碼儘量獨立,方便單元測試、重構、理解和維護;
糟糕的註釋示例:
/* 一個整數 */ int i; /* i從0迴圈到8 */ for (i=0; i<=8; i++) // 變數命名的問題 int bianliang; // 變數命名的問題 class MyView extends View // 圈複雜度的問題 boolean isValid(String content){ if(null != content){ if(isSpaceEnough()){ if(isNetWorkOk()){ if(isInOtherThread()){ for(int index = 0; index < N; index++){ ...... } } } } } }
編碼風格體現了開發人員的基本素質,
排版規範
程式塊要採用縮排風格編寫,縮排為4個空格;
較長的語句、表示式或引數(>80字元)要分成多行書寫,控制每行在80個字元以內;
不允許把多個短語句寫在一行中,即一行只寫一條語句;
if、for、do、while、case、switch、default等語句自佔一行,且執行語句無論多少都要加括號{};
相對獨立的程式塊之間、變數宣告之後必須加空行;
空行將邏輯相關的程式碼段分隔開,以提高可讀性。下列情況應該使用空行:
1. 一個原始檔的兩個片段(section)之間;
2. 類宣告和介面宣告之間;
3. 兩個方法之間;
4. 方法內的區域性變數和方法的第一條語句之間;
5. 一個方法內的兩個邏輯段之間,用以提高可讀性;
6. 通常在變數宣告區域之後要用空行分隔,常量宣告區域之後要有空行分隔,方法宣告之前要有空行分隔。
建構函式有多個時,要依據引數少的在前面,引數多的在後面的原則編寫程式碼,提高程式碼可讀性;
程式碼排版按照成員變數宣告、系統回撥、公有方法、protected方法、私有方法、內部類的順序;
不允許將大塊業務程式碼直接寫在系統回撥方法中,必須抽離成方法供系統回撥呼叫,eg:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_dictation_layout); // 將初始化程式碼封裝成方法供系統回撥呼叫,不要將例項化程式碼直接放在系統回撥方法裡面 initDictation(); } private void initDictation(){ findViews(); getData(); showContent(); }
為了提高程式碼的可讀性,保證每個方法功能單一,單個方法程式碼量控制在50行以內,最多不能超過200行,並且應儘量減少方法之間的耦合;
左大括號放置在行尾,右大括號單獨佔一行;
靜態類的構造方法需要私有化,eg:
public class ArrayUtils { private ArrayUtils(){ } public static <V> boolean isEmpty(V[] sourceArray) { return (sourceArray == null || sourceArray.length == 0); } }
註釋規範
JAVA程式有兩類註釋:
1. 一類是實現性註釋(implementation comments)
2. 另一類是文件型註釋(documentation comments)。
其中,實現性註釋有兩種格式,/…/ 和//。文件型註釋是JAVA程式所獨有的,在/ …/中限定。文件型註釋能夠被javadoc檔案工具提取到HTML檔案中。
注意:
1. 過於頻繁的註釋常常意味著程式碼質量較低。當你覺得必須頻繁添加註釋時,應考慮重寫該段程式碼了。
)或者其它字母圍成的矩形框中;註釋中不應帶有特殊註釋字元如製表(form-feed)和退格符(backspace)。
文件註釋基本原則: *1. 註釋應能使程式碼更加明確;
2. 避免註釋部分的過度裝飾;
3. 保持註釋部分簡單、明確;
4. 在編碼以前就應開始寫註釋;
5. 註釋應說明設計思路而不是描述程式碼的行為。
類註釋
每一個類都必須要包含如下格式的註釋,以說明當前類的功能等。
/** * @author 作者 * 實現的主要功能。 * 建立日期 * 修改者,修改日期,修改內容。 */
方法註釋
關鍵方法或者需要特別說明的方法都需要新增如下格式的註釋,包括當前方法的用途、當前方法引數的含義、當前方法返回值的內容和丟擲異常的列表。
/** * 方法的一句話概述 * <p>方法詳述(簡單方法可不必詳述)</p> * @param s 說明引數含義 * @return 說明返回值含義 * @throws IOException 說明發生此異常的條件 */
類成員變數和常量註釋
關鍵成員變數或者需要說明的成員變數和常量需要使用 java doc 形式的註釋,以說明當前變數或常量的含義
/** * XXXX含義 */
其他註釋;
方法內部的註釋如果需要多行,使用/?? /形式,如果為單行是用//??形式的註釋。不要在方法內部使用 java doc 形式的註釋“/*?? /”。
XML 註釋;
如果當前 layout 或資源需要被多處呼叫,或為公共使用的 layout , 則需要在 xml 寫明註釋。要求註釋清晰易懂。
註釋與所描述內容進行同樣的縮排;
與doc相關的標籤如下表
1. @author:作者的名稱;類、介面;說明特定某一段程式程式碼的作者。每一個作者各有一個標記。
2. @deprecated:類、方法;說明該類的應用程式程式設計介面 (API) 已被廢棄,因此應不再使用。
3. @exception:name description;說明由方法發出的異常。一個異常採用一個標記,並要給出異常的完整類名。
4. @param:name 引數名的描述;用來說明傳遞給一個方法的引數,其中包括引數的型別/類和用法。每個引數各有一個標記。
5. @return:方法返回值的描述;若方法有返回值,對該返回值進行說明。應說明返回值的型別/類和可能的用途。
例如:
@see 類名類、介面、方法、欄位 在文件中生成指向特定類的超文字連結。可以並且應該採用完全合法的類名。 @see ClassName#member functionName 類、介面、方法、欄位在文件中生成指向特定方法的超文字連結。可以並且應該採用完全合法的類名。 @version 版本號類、介面說明特定一段程式碼的版本資訊。
命名規範
命名的基本原則:
1. 命名的格式:[作用區間]+釋義+型別,比如設定介面的佈局檔案:activity_setting_layout,設定按鈕的ID:settingBtnId,成員變數設定按鈕:mSettingBtn等。
2. 使用完整的英文描述符準確描述變數variable/域field/類class;
3. 好的命名能夠減少不必要的註釋和理解程式碼的難度,應儘量做到見名知意,比如settingBtn、feedBackLayout、getUpdateInfo、getCurrentTime、setUserInfo, 而諸如x1、y1、my、main 等命名不能反映任何命名含義而且造成程式碼難以理解、維護和改進。
4. 採用應用領域相關的術語來命名,軟體開發人員應注意軟體使用者的一些約定術語,不應當隨意的創造術語。這會降低軟體的易維護性。
5. 採用大小寫混合的方式提高命名的可讀性一般情況下應該用小寫字母來命名,其中類(class)和介面(interface)名稱的首字母用大寫。
6. 命名中應該慎用縮寫命名。如要採用,則應採用統一的縮略規則,並且在文中的相應部分統一採用縮寫。例如,採用num作為number的縮寫,那麼在整個文件中應該始終使用該縮寫。
7. 避免太長的命名,命名的長度一般小於30個字元,最好不要超過15個字元。避免採用僅有大小寫不同命名。
8. 命名時應避免採用幾乎相同的名稱。例如,變數名稱persistentObject和persistentObjects不應當同時運用;anSqlDatabase和anSQLDatabase也不應同時使用。
9. 有時名稱中會含有固定的縮略詞,例如SQL代表Standard Query Language. 而在命名時sqlDatabase和SqlDatabase就比sQLDatabase和SQLDatabase易於閱讀。
10. 避免以下劃線開頭的命名。
包命名
命名規則:字母全部採用小寫,以com.eebbk開始,後面跟有模組名稱,再後面為層級名稱。如:com.eebbk.模組名.層級名:
com.eebbk.musicplayer.activity
對於功能較多的大模組,可增加功能名一級。如:com.eebbk.模組名.功能名.層級名:
com.eebbk.english.pointread.view
類和介面的命名
命名規則:採用大小寫混合的方式,每個單詞的首字母大寫。儘量使你的類名簡潔而富於描述。使用完整單詞,避免縮寫詞(除非該縮寫詞被更廣泛使用,像URL,HTML),由於類是設計用來代表物件的,所以在命名類時應儘量選擇名詞。如:
class PhotoAdapter; class MusicPlayer; class VideoInfo; class ImageSprite;
介面使用I開頭,抽象類使用A開頭。如:
class IVideo; class ASprite;
方法的命名
命名規則:方法名是一個動詞,採用大小寫混合的方式,第一個單詞的首字母小寫,其後單詞的首字母大寫(小寫字母開頭,任意字母、數字組成)。例如:
public void run(); public String getBookName();
類中常用方法的命名:
1. 類的獲取方法(一般具有返回值)一般要求在被訪問的欄位名前加上get,如getFirstName(),getLastName()。一般來說,get字首方法返回的是單個值,find 字首的方法返回的是列表值;
2. 類的設定方法(一般返回型別為 void):被訪問欄位名的前面加上字首set,如setFirstName(),setLastName();
3. 類的布林型的判斷方法一般要求方法名使用單詞is或has做字首,如isPersistent(),isString()。或者使用具有邏輯意義的單詞,例如equal或 equals。
4. 類的普通方法一般採用完整的英文描述說明成員方法功能,第一個單詞儘可能採用動詞,首字母小寫,如openFile(),addCount()。
5. 構造方法應該用遞增的方式寫(引數多的寫在後面)。
非靜態成員命名
命名規則:使用駝峰規則, m與任意一大寫字母開頭,由字母、數字組成,如mUserName,mMediaPlayer;
常量命名
命名規則:類常量的宣告,應該全部大寫,單詞間用下劃線隔開(以大寫字母開頭,由大寫字母、數字和下劃線組成),例如:
static final int MIN_WIDTH = 4; static final int MAX_WIDTH = 999;
區域性final變數與catch引數:
命名規則:小寫字母開頭,由字母、數字組成,eg:
final int age;
區域性非final變數與catch引數:
命名規則:小寫字母開頭,由字母、數字組成,eg:
int userCount;
異常命名
自定義異常的命名必須以Exception為結尾,以明確標示為一個異常。
layout 命名
layout xml的命名必須以全部單詞小寫,單詞間以下劃線分割,並且使用名詞或名詞片語,即使用 “[作用區間]釋義 型別”來命名。
1. layout命名:activity_釋義_layout.xml,例如:
activity_setting_layout.xml;
- Dialog命名:dialog_釋義_layout.xml,例如:
dialog_app_update_layout.xml
- Popupwindow命名:popupwindow_釋義_layout,例如:
popupwindow_grade_list_layout.xml
- Adapter中項的佈局命名:listview/gridview_item_釋義_layout,例如:
listview_item_grade_layout
- 包含項的命名:include_釋義_layout,例如:
include_top_bar_layout.xml
id 命名
layout中所使用的id要求能夠通過id直接理解當前元件要實現的功能,命名規則為:功能+型別+Id;如:顯示課文名稱的TextView,應命名為:
@+id/lessonNameTxtId;
如:輸入使用者名稱的EditText,應命名為:
@+id/userNameEditTxtId;
資源命名
layout中所使用的所有資源(如 drawable,style,diem 等)要求能夠通過 id 直接理解當前元件要實現的功能,命名規則為:功能+型別+[normal/press]+[索引值],如: 設定介面的背景圖,應命名為:
setting_bg;
設定按鈕正反選圖,應分別命名為:
setting_btn_normal; setting_btn_press;
性別勾選checkbox正反選,應命名為:
sex_checkbox_normal; sex_checkbox_press;
物體移動AnimationDrawable動畫,應命名為:
dog_move_0 dog_move_1 dog_move_2
常用的反義片語
add / remove;
begin / end;
create / destroy;
insert / delete;
first / last;
get / set;
increment / decrement;
put / get;
add / delete;
lock / unlock;
open / close;
min / max;
old / new ;
start / stop;
next / previous;
source / target;
show / hide;
send / receive;
source / destination ;
cut / paste;
up / down
常用的縮寫
Button,簡寫:Btn(btn);
RadioButton,簡寫:Rbtn(rbtn);
ImageButton,簡寫:Ibtn(ibtn);
TextView,簡寫:Tv(tv);
ImageView,簡寫:Iv (iv);
ListView,簡寫:Lv(lv);
ProgressBar,簡寫:Pbar(pbar);
EditText,簡寫:Edtv(et);
ScrollView,簡寫:Sclv(scly);
CheckBox,簡寫:Chk(chk);
RelativeLayout,簡寫:Rlyt(rlyt);
LinearLayout,簡寫:Llyt(llyt);
TableLayout,簡寫:Tlyt(tlyt);
AbsoluteLayout,簡寫:ALyt(alyt);
FrameLayout,簡寫:Flyt(flyt);
RadioGroup,簡寫:Rgp(rgp);
SharedPreferences,記那些:Sp(sp)。
回撥函式以必須以on開頭;
識別符號應當使用完整的英文描述,識別符號的命名應當符合“min-length && max-information”原則,謹慎使用縮寫;
說明:
1. 對於識別符號應當使用完整的英文進行描述,對於整個描述較長的,可對單詞進行縮略;
2. 對單詞的縮略可按較短的單詞可通過去掉“母音”形成縮寫,較長的單詞可取單詞的頭幾個字母形成縮寫,一些單詞有大家公認的縮寫,常用單詞的縮寫必須統一。
3. 協議中的單詞的縮寫與協議保持一致。對於某個系統使用的專用縮寫應該在某處做統一說明。設計命名中應該慎用縮寫命名。如要採用,則應採用統一的縮略規則;
注意靜態常量的宣告次序(方括號中的內容為可選):[作用域]+[static]+[final]+型別+屬性名稱 = 初始值;比如:
public static final int NAME = 5;
JAVA程式碼標準規則
禁止出現多餘的修飾符;
檔案長度控制在 2000 行以內;
方法職責要單一,要求方法行數控制在200行以內 ;推薦一個方法儘量不要超過50行,如果方法太長,說明當前方法業務邏輯已經非常複雜,那麼就需要進行方法拆分,保證每個方法只作一件事。
一個方法的引數儘可能的不要超過5個;
控制語句,所有if、switch條件分支必須用{}包括起來,即便是隻有一句:
if (***){ //do something...... } if (***) i = 0; //不要使用這種
異常的捕捉處理
1. 通常的思想是隻對錯誤採用異常處理:邏輯和程式設計錯誤,設定錯誤,被破壞的資料,資源耗盡等等;
2. 通常的法則是系統在正常狀態下以及無過載和硬體失效狀態下,不應產生任何異常;
3. 最小化從一個給定的抽象類中匯出的異常的個數;
4. 對於經常發生的可預計事件不要採用異常;
5. 不要使用異常實現控制結構;
6. 若有finally子句,則不要在try塊中直接返回,亦不要在 finally 中直接返回。
資料庫操作、IO操作等需要使用結束close()的物件必須在try -catch-finally 的finally中close()。示例:
try{ }catch(IOException ioe){ }finally{ try{ out.close(); }catch (IOException ioe){ } }
訪問控制,僅對需要對外公佈的方法、變數採用public,其餘的儘量使訪問域最小化。
禁止使用立即數,用有意義的標識來替代,涉及物理狀態或者含有物理意義的常量,不應直接使用數字,必須用有意義的靜態變數來代替。如下的程式可讀性差:
if (state == 0){ state = 1; ...// program code }
應改為如下形式:
private final static int TRUNK_IDLE = 0; private final static int TRUNK_BUSY = 1; private final static int TRUNK_UNKNOWN = -1; if (state == TRUNK_IDLE){ state = TRUNK_BUSY; ...// program code }
編碼格式,所有工程必須是UTF-8編碼;
程式碼優化規則
避免在迴圈表示式中呼叫函式或方法,提高程式碼效能,反例:
class CEL{ void method (Vector vector){ // 違例 for (int i = 0; i < vector.size (); i++){ System.out.println(i); } } }
正例:
class CELFixed { void method (Vector vector){ int size = vector.size (); for (int i = 0; i < size; i++) { //正確 System.out.println(i); } } }
如有開啟的資料流,在finally語句塊中關閉資料流,避免潛在的bugs,反例:
public class CS { public void method (java.io.File f){ try{ java.io.FileInputStream fis = new java.io.FileInputStream (f); fis.read (); fis.close (); }catch (java.io.FileNotFoundException e1){ System.out.println("File not found"); }catch (java.io.IOException e2){ System.out.println("I/O Exception"); } // 違例: 如果有異常發生'fis'永遠不會關閉 } }
正例:
public class CSFixed{ public void method (java.io.File f){ try{ java.io.FileInputStream fis = new java.io.FileInputStream (f); fis.read (); }catch (java.io.FileNotFoundException e1) { System.out.println("File not found"); }catch (java.io.IOException e2){ System.out.println("I/O Exception"); }finally{ fis.close (); } } }
使用’System.arrayCopy()’替代迴圈拷貝陣列,優化效能,反例:
public class IRB{ int[] copyArray (int[] array){ int length = array.length; int[] copy = new int [length]; for (int i = 0; i < length; i++){ //違例 copy[i] = array[i]; } return copy; } }
正例:
public class IRB{ int[] copyArray (int[] array){ int length = array.length; int[] copy = new int [length]; //正確 System.arraycopy(array, 0, copy, 0, length); return copy; } }
避免在迴圈語句內部出現”try/catch/finally”,優化程式碼,反例:
public class TRY{ void method (FileInputStream fis){ for (int i = 0; i < size; i++){ try{ //違例 sum += fis.read (); }catch (Exception e){ } } } private int _sum; }
正例:
public class TRY{ void method (FileInputStream fis){ try{ //正確 for (int i = 0; i < size; i++){ sum += fis.read (); } }catch (Exception e) { } } }
在迴圈體中避免例項化物件或宣告變數,提高程式碼執行效能,反例:
public class LOOP{ public void method(int max){ for (int i = 0; i < max; i++){ //違例 StringBuffer sb = new StringBuffer(); sb.append("loop: "); sb.append(i); System.out.println(sb.toString()); } } }
正例:
public class LOOPFixed{ public void method(int max){ //正確 StringBuffer sb = new StringBuffer(); for (int i = 0; i < max; i++){ sb.append("loop: "); sb.append(i); System.out.println(sb.toString()); sb.setLength(0); } } }
try語句塊內部儘量精簡,try語句塊內部程式碼執行效率比較低,因此儘量只把可能會產生異常的程式碼書寫在try語句塊內部,不會產生異常的程式碼不要寫在try語句塊內
其它規定
專案相關的文件必須放在主工程的doc資料夾下;
每次釋出版本前,要使用Android Studio→Inspect Code…對程式碼的靜態質量做檢測,儘早解決編碼規範和編碼質量的問題。