前言
目前公司的項目已經全面使用Kotlin,轉換的過程的確不是怎麼讓人舒適,但是讓人欣慰的是結局是讓人滿意的。Kotlin的確可以讓代碼簡潔,安全並且高效。這裏分享一下,在使用Kotlin中那些讓人覺得舒適的地方。
- 字符模板
- 空安全
- 延遲加載
- 方便易讀的循環
- 強大易用的迭代器
- 默認參數
- DataClass
- 簡短而強大的標準函數庫
- 通吃的when(結合密封類會讓代碼更舒適)
- 擴展
- 簡單的Bundle 快速的Parcelable
- 未完待續..
字符模板
開發中難免需要根據多個字段去拼接一條字符串做展示,在過長或者過於複雜的數據邏輯的時候,用Java實現起來都過於冗長。Kotlin 使用 $ 放在變量名的前面去表達字符串中的變量和表達式,從而簡化了這一過程。
val str = "hello"
// str length : 5
print("$str length: {$str.length}")
空安全
在使用Java開發Android的過程中,避免不了大量的空安全判定代碼,介於Kotlin要很好的兼容Java,在這個問題上Kotlin設計一整套新的類型系統(這裏不作研究)來完善優化它。
所有的類型都分爲可空和不可空類型,並且針對不可空類型強制要求初始化,在一開始就讓開發者高標準的、嚴謹的使用變量,是一種規範性的要求。但是可空類型可能會在程序中更廣泛的應用,針對這一點,Kotlin也有Elvis 操作符來進行安全訪問或者避免空值情況,見簡潔代碼。
// 不可空類型(使用前必須初始化)
var notCanNullInt: Int = 0
// 可空類型
var canNullInt: Int? = null
// 安全訪問
print("${canNullInt?.toShort()}")
// 避免空值 爲空給與一個默認值
val age = canNullInt ?: 18
// 爲空返回
val time = canNullInt ?: return
延遲加載
這一點可以說是對不可空類型的更進一步優化,開發中總有一些變量是在某些時機纔會被初始化,而不是類加載的時候就加載。延遲加載是很好的東西,可以省去初始化的成本,在變量真正被需要的時候才被初始化。
val userInfo: UserInfo by lazy { UserInfo() }
lateinit var person: InvationPerson
方便易讀的循環
Kotlin有區間的概念,這個概念讓創建循環更加易讀方便。
// print :0 1 2 3 4 5 6 7 8 9 10
for (i in 0..10) {
print("$i ")
}
// print :10 9 8 7 6 5 4 3 2 1 0
for (i in 10 downTo 0) {
print("$i ")
}
// print :0 2 4 6 8 10
for (i in 0..10 step 2) {
print("$i ")
}
// print :0 1 2 3 4 5 6 7 8 9
for (i in 0 until 10) {
print("$i ")
}
val map = mapOf("a" to 1, "b" to 2)
// print :a - 1 b - 2
for ((key, value) in map) {
print("$key - $value")
}
強大易用的迭代器
遍歷集合是基操,對於一些稍微複雜一點的數據邏輯,Java實現起來並不友好。當然後面有了RxJava來進行補救,不過Kotlin做的似乎要更好一點。(這裏就不討論Kotlin的集合框架架構了)
val list = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9)
list.forEach { print(it) }
// 映射
val listUp = list.map { it + 2 }
// 過濾
val listFilter = list.filter { it % 2 == 0 }
// asSequence 懶處理 map filter中都存在遍歷操作 asSequence可以將它們合併起來 只存在一次遍歷 提升性能
val listMore = list.asSequence().map { it + 2 }.filter { it % 2 == 0 }.toList()
asSequence 對提升效率大有裨益,其他的操作就不一一列舉了
默認參數
重載是很比較常見的操作,但是有時候這種方式會出現很多相同的模板代碼。Kotlin的默認參數,可以給參數指定默認值,並且在調用的時候像給變量賦值一樣給參數賦值而不用像Java一樣非要按照順序去傳值。並且因爲具有默認值的原因,所以調用的時候可以根據具體情況傳遞參數,更加靈活、更加易讀和簡潔。
class Point(val x: Float = 0F, val y: Float = 0F)
val x = Point(x = 10F)// x 10 y 0
val y = Point(y = 10F)// x 0 y 10
val xy = Point(x = 10F, y = 10F)// x10 y10
DataClass
開發中Bean文件是必不可少的,但是Java的Bean文件大部分都是模版代碼,雖然有插件自動生成,但是依然會覺得比較繁瑣,Kotlin可以將這些類申明爲Data類,這些類會默認實現equals(),hashCode(),toString() 和copy() 方法,從幾十行Java代碼簡潔到幾行代碼,Kotlin只用聲明 一個data class
data class Person(
val name: String,
val age: Int,
val sex: Int
){
//....
}
簡短而強大的標準函數庫
這是Kotlin提供的函數庫,使用後會簡化不少的樣板代碼。稍微不一樣的地方是它們的this和it各自指向不一樣,以及返回值得不一樣,使用得時候根據具體得情況來就可以了.
run
val str = "a"
val res = str.run{
// this 指向 "a" it沒有指向
// 可以直接訪問對象得屬性
print(length)
1 // 最後一行返回值爲1
}
let
val str = "a"
val res = str.let{
// this 指向當前class
// it 指向a
print(it.length)
"let" // 返回值"let"
}
with
val res = with(user){
// this 指向user it無指向
println(age)
println(name)
"with" // 返回值
}
apply
val str = "a"
val res = a.apply{
// this指向a it 無指向
2 // 返回值
}
通吃的when
對於Java的Stwich再熟悉不過,但是它使用起來有比較多的限制,有時候面對複雜的邏輯會顯得乏力。Kotlin的when表達式可以匹配幾乎任何東西(字面值,枚舉,數字,範圍,類型,表達式,甚至函數(kotlin函數至上)) 簡單感受下:
fun whenTest(number: Number?): String {
return when (number) {
null, 0 -> "empty"
1 -> "tiny"
in 2..5 -> "small"
is Long -> "big number"
else -> "unKnow"
}
}
當然有時候使用when會有一些比較麻煩的事情,比如對else情況的處理,因爲你的程序中明明只有這麼幾種情況,但是你卻不得不寫上關於else的情況處理,這樣的代碼讓人覺得不安心,也降低了可讀性,這個時候可以結合Koltin的密封類來處理,比如對網絡情況的回執,對錯誤的處理,Android對RecyclerView的適配中多中ViewHolder的處理
// 密封類的存在讓整個過程中可能出現的情況更加嚴謹
sealed class NetWorkResult
data class Success(val resJson: String) : NetWorkResult()
data class Failure(val error: Error) : NetWorkResult()
// 代碼更加易讀
fun netWorkTest(result: NetWorkResult) {
when (result) {
is Success -> {
showResult(result.resJson)
}
is Failure -> {
showError(result.error)
}
}
}
擴展
擴展可能是最受歡迎的一個特性,因爲它可以讓你少寫很多工具類,並且讓代碼看起來更易讀,更簡潔。比如做一個防止重複點擊的操作。
// 擴展點擊事件屬性(重複點擊時長)
var <T : View> T.lastClickTime: Long
set(value) = setTag(1766613352, value)
get() = getTag(1766613352) as? Long ?: 0
// 重複點擊事件綁定
inline fun <T : View> T.singleClick(time: Long = 800, crossinline block: (T) -> Unit) {
setOnClickListener {
val currentTimeMillis = System.currentTimeMillis()
if (currentTimeMillis - lastClickTime > time || this is Checkable) {
lastClickTime = currentTimeMillis
block(this)
}
}
}
簡單的Bundle 快速的Parcelable
一開始我並沒有注意到這個特性,因爲項目是組件化開發,在跳轉傳值上都採用了ARouter,但是當我發現Kotlin對這個做的改造的時候還是非常開心~
今年年初我花一個月的時間收錄整理了一套知識體系,如果有想法深入的系統化的去學習的,可以私信我【安卓】,我會把我收錄整理的資料都送給大家,幫助大家更快的進階。