本文是學習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
來替換參數,必須明確聲明參數。