Coding Style
前言
Android Coding Style 包含以下
Java Coding Style
Kotlin Coding Style
Android各種命名規則
Android 需要遵守的規則
這邊程式碼範例會以Kotlin的語法來做說明,由於Java與Kotlin的CodingStyle規則基本上相同。所以,只有當Java 部分需要特別解釋時,才會補上Java範例。
PS.Kotlin在Android平台上會轉譯成Java,如果有會Java但不懂Kotlin的,可以在Android Studio工具列上點擊 Tools -> Kotlin -> Show Kotlin ByteCode , 在Kotlin ByteCode上點擊 Decompile 就會顯示Java版本的程式碼
命名
程式碼除了註解與字串外,不得使用中文字
UnitTest或AndroidTest的方法名稱可以使用中文以方便辨識功能
禁用region*新增範例 但是別這樣寫
// region 說明文字
你的程式碼
// endregion
所有 MagicNumber 一律宣告 常數 或 變數 或 enum(列舉) 或 seal class(for kotlin),禁止直接在程式碼內使用
Don't
for(int i = 0; i < 10; i++) {
...
}
Do
final int MAX_COUNT = 10;
for(int i = 0; i < MAX_COUNT; i++) {
...
}
所有要對外的欄位:
Java一律使用屬性的方式,禁止直接使用 public 變數公開
Kotlin直接使用變數()。沒有必要公開的屬性就不該公開
禁用無大刮號單行else (DanglingElse)
你不該交出 Compile 後有一堆警告的程式碼,更不該交出有 Error 的程式碼
Java變數使用小駝峰命名,private變數不需要m開頭
kotlin變數使用小駝峰命名
常數成員一律 全大寫配底線分隔 => VERSION_NUMBER
在命名時,請不要自己縮寫單字來命名,能用的縮寫只有大家常用的縮寫。 例如:
ResponseMessage
縮寫成RspMsg
上面的Message
縮寫成Msg
,大多數人都還看得懂。但是將Responses
縮寫成Rsp
,如果不看原本的樣子,基本上是沒辦法看懂的,所以如果要用縮寫,只有像是Msg
這樣大家都可以懂的縮寫可以用,不然請好好的把原本的單字寫出來。 另外,使用縮寫時大小寫不照原縮寫,應使用大寫開頭+小寫的方式,即使是像iOS
這樣,大多數人習慣第一個i
小寫的,也請這樣寫IosVersionSetting
,而不是iOSVersionSetting
。
以下針對不同地方的命名做詳細規則的說明
檔案的命名
檔案名以大駝峰式命名。例如:NumberExtension.kt,NumberExt.kt
檔案名稱與類別同名 正確寫法:
// 檔名:MyClass.kt
class MyClass {
}
錯誤寫法:
// 檔名:MyClass.kt
class OtherClass {
}
原則上一個檔案中只有一個主要類別 例外:非泛用類別可以直接寫在類別裡面 正確寫法:
// 檔名:FirstClass.kt
class FirstClass {
}
// 檔名:SecondClass.kt
class SecondClass {
}
錯誤寫法:
// 檔名:FirstClass.kt
class FirstClass {
}
class SecondeClass {
}
擴充方法檔案命名
檔名以擴充的物件命名加上Extension、Ext為後綴。例如:NumberExtension.kt,NumberExt.kt
檔案名以大駝峰式命名。例如:NumberExtension.kt,NumberExt.kt,NumberUtils.kt Extension寫法與用法 工具類方法檔案命名
檔名以目標功能命名加上Helper、Utils為後綴,例如:ChartCalculateHelper.kt, DateTimeFormatUtils.kt Helper與Utils的差別 參考
檔名以大駝峰式命名
類別的命名
大寫駝峰式命名 正確寫法:
class Setting {
}
錯誤寫法:
class setting {
}
名詞 或 形容詞+名詞 正確寫法:
class NestedStucture {
}
錯誤寫法:
class CalculateStock {
}
類別繼承Android原生類別時在名稱尾部加上原生類別的名稱,需要寫的有Application,Activity,Fragment,Service,Adapter,ViewHolder。
正確寫法:
class ArticleViewHolder(cell: ConstraintLayout) : RecyclerView.ViewHolder(cell) {
...
}
錯誤寫法:
class ArticleCell(cell: ConstraintLayout) :RecyclerView.ViewHolder(cell) {
...
}
方法的命名
使用小駝峰命名
使用 動詞(load, fetch, preLoad, ...) 或 動詞+名詞(getData, fetchFileList, ...) 作為命名
fun loadData(){
...
}
方法參數或區域變數的命名 ,參數或區域變數用小寫開頭變數名(小駝峰命名)
fun getFundList(token: String, pushToken: String){
...
}
有Boolean回傳值時的命名,以is, can, has 或xxxable為結尾,例如:isOpened , canRead, hasValue, visiable
fun isFinish : Boolean{
return false
}
如果方法的參數,無法用一行表達時,須將參數個別單獨為一行。
fun sayHello(): String {
return "Hello"
}
只有Kotlin可以寫成一行
fun sayHello(): String = "Hello"
如果callBack方法以Lambda寫法 Lambda傳遞的參數放在第一行
setOnclickListener { prop ->
val propertyValue = prop.get(obj)
}
Package name 的命名
全部小寫
Resource 的命名
全小寫 規則:以畫面使用的位置+功能 來命名,例如以下
activity_xxx.xml
fragment_xxx.xml
item_xxx.xml
layout_xxx.xml
dialog_xxx.xml
shape_xxx.xml
selector_xxx.xml
.....
例外: 模組因Gradle合併資源可能會與專案衝突,所以命名要加prefix 舉例: 社團模組之發文頁Layout
community_layout_activity_newpost
自選股模組之編輯自選股頁Layout
customgroup_layout_activity_editcustomgroup
View Id的命名
規則:功能+使用元件 來命名,例如以下
login_textView
reply_us_editText
xxx_textView
xxx_editText
xxx_button
xxx_linearLayout(constraintLayout,..)
...
修飾詞
可見性修飾詞
Kotlin 可見性修飾詞 private、 protected、 internal 和 public ,預設可見性是 public。
Java 可見性修飾詞 private、package-private、 protected 和 public,預設可見性是 package-private。相關連結
順序
public / protected / private / internal
expect / actual
final / open / abstract / sealed / const
external
override
lateinit
tailrec
vararg
suspend
inner
enum / annotation
companion
inline
infix
operator
data
public protected private
abstract default
static final
transient volatile
synchronized native strictfp
型別
對於Kotlin基礎型別有疑惑的,可以去這邊尋找答案,這邊只寫需要注意的部分。Java的往這邊。
轉型
數值向下轉型會有遺失資料的風險
安全轉型 vs 不安全轉型
安全轉型方式
kotlin
安全
open class Car {
}
class Taxi : Car() {
}
fun main() {
val tempCar: Car = Car()
val tempTaxi: Taxi? = tempCar as? Taxi
if (tempTaxi == null) {
return
}
}
不安全
val tempTaxi: Taxi = Taxi()
val tempCar: Car = tempTaxi as Car // 轉型成功
if(tempCar is Car) {
tempCar.xxx()
}
java 安全
class Car {
}
class Taxi extends Car {
}
Car tempCar = new Taxi();
if (tempCar instanceof Taxi)) {
Taxi tempTaxi = (Taxi)tempCar;
do something..
}
不安全
class Car {
}
class Taxi extends Car {
}
Car tempCar = new Taxi();
Taxi tempTaxi = (Taxi)tempCar;
do something..
字串
字串的不變性請參考這裡
不要什麼東西都存字串,成本很重。
有需要迴圈來組字串時只能使用StringBuilder
除了需要在迴圈裡組字串情況外,都使用+號或StringTemplate,使用+號是因為在編譯時會把+轉成StringBuilder來實現,所以不必擔心記憶體使用問題,而且使用+能使可讀性與可維護性提升
// StringTemplate範例
val s = "abc"
println("$s.length is ${s.length}")
三個以上參數時不要用String.format,會造成可讀性與維護性下降
// don't
String.format("first:%d second:%d third:%d",a,b,c)
字串轉型態 可以直接 "String".toIntOrNull()、"String".toDoubleOrNull()....
比較字串可以直接用 "FirstString" == "SecondString" 的寫法 ,Kotlin有幫你做好了。如果需要忽略大小寫可以這樣寫 "FirstString".equals("SecondString",true)
請使用 string.IsNullOrEmpty() 來檢查 null or 空字串,而非 str == null 或 str == ""
Java 特別注意的部分:
[Java String Concatenation: Which Way Is Best?]https://redfin.engineering/java-string-concatenation-which-way-is-best-8f590a7d22a8
比較字串請不要用以下的寫法 ,這是比較物件是否相等
if( "originalString" == "compareString" )
正確寫法為
if( "originalString".equals("compareString") )
或
if( "originalString".compareTo("compareString") == 0 )
Nullable與NonNullable
Kotlin的型別皆可以Nullable,因此在使用上有幾項要注意的地方
非必要不將型別、屬性及欄位設為Nullable型態
非必要不使用!!(斷定NonNullable),因為這樣就拋棄了Kotlin自動安全檢查null的優勢
若是在一定要用到值的時候則可以使用!! or requireNotNull,以確保流程正確,但是如此做需要做例外處理,不可直接使APP崩潰
範例: LiveData已經設定為Boolean,但是方法因為是從Java編譯,所以還是可能為Null,故可以使用!!orrequireNotNull進行取值
val isLoading: LiveData<Boolean> = MutableLiveData<Boolean>(false)
val state = isLoading.value!!
註解
註解可以記下開發流程和緣由和思緒流程,特殊的邏輯一定要寫註解。 註解要和程式碼一起維護,不要留下過時的註解。
單行註解 可用 /* ... */ 或 // ... 。
// End-Of-Line Comments
/* Single-Line Comments */
區塊註解 註解區塊的縮排,和其接連的程式碼同一層級。可用 /* ... / 或 // ... 。若是這種註解風格/ ... /有多行時,其子行的起始必需有,而該星號需對齊上一行的 *。
/*
* This is
* okay.
*/
// And so
// is this.
/* Or you can
* even do this. */
*這邊有撰寫一個範例: 如下
/**
* 取得選擇年月的月初日期
* @param twYear 民國 X 年
* @param month 月 (不必 -1)
* @return 西元年月日 格式 = "yyyy/MM/dd"
*/
Javadoc 置於 Class 宣告、Method 宣告、Field 宣告或 Property 宣告之前。 必須要寫 Javadoc 的有 public class 以及所有的 public 或 protected 成員 (member) 。
使用/** ... /註解,其子行的起始必需有,而該星號需對齊上一行的 *。
/**
* Multiple lines of Javadoc text are written here,
* wrapped normally...
*/
public int method(String p1) {
...
}
如果只有單行可以縮成
/** An especially short bit of Javadoc. */
不用寫 Javadoc 的例外
在子物中覆寫 (override) 父類別的方法不一定要寫上 Javadoc,若執行邏輯中有不易理解的(若不清楚可以徵詢其他人CodeReview)則需要寫上註解。
有些「簡單、明確」的方法也不一定要寫上 Javadoc,像是
getFoo
這種簡明的案例,好像除了寫上「返回 foo 值」也什麼好寫的。但如果對於一般人來說並不能馬上知道 Foo 是什麼意思,那就要寫 Javadoc。方法的回傳
TODO 善用 IDE 的 TODO 功能,對那些臨時的、短期的解決方案,或已經夠好但仍不完美的程式碼使用 TODO 或 FIXME 註解。 TODO 是總稱, FIXME 是細分。 用 FIXME 來表示存在問題或優先度較高的 TODO 事項(可選)
// TODO: 2019/2/14 待重構
// FIXME: 2019/2/14 有未知的狀況會Crash
*這邊有示範如何快速撰寫todo與尋找todo
註解程式碼 請不要註解程式碼,不如直接拿掉。 若真的有需要,一律使用// ...。
擴充方法
放置位置:放在$root/extension的資料夾底下
例外處理
不要忽略例外 Don't
fun setServerPort(value : String) {
try {
serverPort = value.toInt()
} catch (e : NumberFormatException) {
}
}
如果沒有要處理,就不要 catch,只在可以處理的地方 catch。
不要直接 catch 最上層的 Exception 或 Throwable Don't
catch (e1 : Exception) {
}
Finally 區塊裡面只用來作資源回收或清理資料結構的工作,或使用 Try-with-resources 來自動處理資源回收。
resource = acquireResource()
try {
useResource(resource)
} finally {
releaseResource(resource)
}
或是
val writer = FileWriter("test.txt")
writer.use {
writer.write("something")
}
不要嵌套 try catch ,會造成可讀性與維護性下降,請把需要try-catch的地方包成一個方法,並把Exception丟出 Don't
try {
...
try {
...
} catch (e2 : WhateverException) {
// Exception Message
}
} catch (e1 : FooException) {
// Exception Message
}
Do
try {
...
throwExceptionMethod()
} catch (e1 : FooException) {
// Exception Message
} catch (e2 : WhateverException) {
// Exception Message
}
附錄
參考網站
https://kotlinlang.org/docs/reference/
https://www.kotlincn.net/docs/reference/
https://blog.csdn.net/u012830807/article/details/17068091
Last updated
Was this helpful?