Kotlin學習(五): 慣用語法和代碼風格(Idioms And Coding Conventions)

Concise

本文是學習Kotlin的慣用語法和代碼風格,與Java的語法和代碼風格有一些相同,也有一些不同。

創建DTO’s(POJOs/POCOs)數據類(Creating DTOs (POJOs/POCOs))

data class Customer(val name: String, val email: String)

這裏的Customer是數據類,在Kotlin中,會自動爲Customer類生成以下方法
- 給所有屬性添加getter方法,如果是var類型的話會添加setter方法
- equals()
- haseCode()
- toString()
- copy()
- 給所有屬性添加component1()component2(),…

函數參數默認值(Default values for function parameters)

可以爲函數的參數設置默認值

fun foo(a: Int = 0, b: String = "") { ... }

過濾list(Filtering a list)

使用擴展函數filter來過濾list

val positives = list.filter { x -> x > 0 }

或者用it來替換x

val positives = list.filter { it > 0 }

判斷實例(Instance Checks)

通過用is來判斷是否屬於某個實例

when (x) {
    is Foo ->  ...
    is Bar -> ...
    else -> ...
}

遍歷map/list(Traversing a map/list of pairs)

for ((k, v) in map) {
    println("$k -> $v")
}

其中k和v可用任意命名

只讀list/map(Read-only list/map)

只讀就是設置爲常量

val list = listOf("a", "b", "c") 
val map = mapOf("a" to 1, "b" to 2, "c" to 3)

訪問map(Accessing a map)

對map的使用

println(map["key"])
map["key"] = value

延時加載(Lazy property)

lazy 用於延時加載,即第一次使用時才執行初始化的操作。

val p: String by lazy {
    // compute the string
}

擴展函數(Extension Functions)

fun String.spcaceToCamelCase() { ... }
"Convert this to camelcase".spcaceToCamelCase()

前面有提到filter擴展函數,擴展函數就是創建可直接使用的方法,例如我要創建一個可直接使用的toast方法,可以這樣寫


fun Context.toast(content: String?) {
    Toast.makeText(this, content, Toast.LENGTH_SHORT).show()
}

調用的時候

// activity裏面
toast("擴展函數")
// 有context的時候
mContext.toast("擴展函數")

創建單例(Creating a singleton)

Kotlin創建單例模式就比較簡單了

object Resource {
    val name = "Name"
}

如果不爲空則…的簡寫(If not null shorthand)

val files = File("Test").listFiles()
// 對files加了不爲空的判斷(?)
println(files?.size) 

如果不爲空則…否則…的簡寫(If not null and else shorthand)

val files = File("Test").listFiles()
// 對files加了不爲空的判斷(?),同時加了爲空的判斷(?:)
println(files?.size ?: "empty") // 如果files爲空則打印empty

如果爲空,則執行語句(Executing a statement if null)

使用?:符號,爲空時執行語句

val data = ...
val email = data["email"] ?: throw IllegalStateException("Email is missing!")
val name = data["name"] ?:let{
      ...
}

如果不爲空,則執行語句(Execute if not null)

使用?符號,加非空判斷,.let{ }是不爲空的時候執行

val data = ...

data?.let {
    ... // 如果不爲空,請執行此塊操作
}

返回 when 判斷(Return on when statement)

返回的時候可以直接用when表達式返回值

fun transform(color: String): Int {
    return when (color) {
        "Red" -> 0
        "Green" -> 1
        "Blue" -> 2
        else -> throw IllegalArgumentException("Invalid color param value")
    }
}

如果一個函數只有一個並且是表達式函數體並且是返回類型自動推斷的話,可以直接等於返回值

fun transform(color: String): Int = when (color) {
    "Red" -> 0
    "Green" -> 1
    "Blue" -> 2
    else -> throw IllegalArgumentException("Invalid color param value")
}

try / catch表達式(‘try/catch’ expression)

Kotlin的try/catch表達式同Java類似,Kotlin可以直接賦值

fun test() {
    val result = try {
        count()
    } catch (e: ArithmeticException) {
        throw IllegalStateException(e)
    }

    // 處理result
}

方法使用Builder模式返回Unit(Builder-style usage of methods that return Unit)

fun arrOfMinusOnes(size: Int): IntArray{
    // 生成一個大小爲size,每個值爲-1的數組
    return IntArray(size).apply{ fill(-1) } // fill(-1)設置爲值爲-1
}

單表達式函數(Single-expression functions)

前面說過如果一個函數只有一個並且是表達式函數體並且是返回類型自動推斷的話,可以直接等於返回值

fun theAnswer() = 42

等同於

fun theAnswer(): Int {
    return 42
}

使用with調用一個對象實例的多個方法(Calling multiple methods on an object instance (‘with’))

class Turtle {
    fun penDown()
    fun penUp()
    fun turn(degrees: Double) 
    fun forward(pixels: Double)
}
val myTurtle = Turtle()
// 如果正常的寫
myTurtle.penDOwn()
for(i in 1..4) {
    myTurtle.forward(100.0)
    myTurtle.turn(90.0) 
}
myTurtle.penUp() 
// 使用with將對象實例引用,代碼減少很多
with(myTurtle) { 
    penDown()
    for(i in 1..4) {
        forward(100.0)
        turn(90.0) 
    }
    penUp() 
}

同樣,在Adapter裏面可以直接使用with來替換holder.itemView


with(holder.itemView) {
       // 名稱
       new_item_text.text = mDatas?.get(position)?.desc
        // 作者
        new_item_user.text = mDatas?.get(position)?.who.let { Constant.NEW_ITEM_USER_NULL }
}

Java 7的try with resources(Java 7’s try with resources)

try-with-resources語句是一個聲明一個或多個資源的 try語句。一個資源作爲一個對象,必須在程序結束之後隨之關閉。
在Java 7 之前, 可以使用finally塊來確保資源被關閉,不管try語句正常地完成或是發生意外。而try-with-resources語句確保在語句的最後每個資源都被關閉 。

val stream = Files.newInputStream(Paths.get("/some/file.txt"))
stream.buffered().reader().use { reader ->
    println(reader.readText())
}

泛型轉換(Convenient form for a generic function that requires the generic type information)

//  public final class Gson {
//     ...
//     public <T> T fromJson(JsonElement json, Class<T> classOfT) throws JsonSyntaxException {
//     ...

inline fun <reified T: Any> Gson.fromJson(json): T = this.fromJson(json, T::class.java)

使用可空的Boolean(Consuming a nullable Boolean)

添加?符號可以讓變量可爲空

val b: Boolean? = ...
if (b == true) {
    ...
} else {
    // `b` 是false或者爲null
}

命名風格(Naming Style)

Kotlin的命名風格與Java的類似
- 使用駱駝命名法(在命名中避免下劃線)
- 類型名稱首字母大寫
- 方法和屬性首字母小寫
- 縮進用四個空格
- ……

冒號(Colon)

在冒號之前有一個空格,冒號分隔類型和超類型(fun foo(a: Int): T),沒有空格,冒號分隔實例和類型(var bar: String):

interface Foo<out T : Any> : Bar {
    fun foo(a: Int): T
}

Lambdas

Kotlin支持Lambdas表達式,在 Lambdas 表達式中,大括號與表達式間要有空格,箭頭與參數和函數體間要有空格。儘可能的把 Lambda 放在括號外面傳入

list.filter { it > 10 }.map { element -> element * 2 }

在短的且不嵌套的Lambdas中,建議使用it替換參數,有嵌套而已有多個參數的Lambdas中,就不能用it來替換參數,必須明確聲明參數。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章