Kotlin 語法上的一些亮眼操作
本文原創,轉載請注明出處。
歡迎關注我的 簡書 ,關注我的專題 Android Class 我會長期堅持為大家收錄簡書上高質量的 Android 相關博文。
寫在前面:
上上周我們創建了第一個 kotlin 的 android 應用。上周我花了一周的時間,在工作之余了解了 kotlin 的語法。感嘆 kotlin 做為“高級”語言與 java相比,展現出來的簡潔、高效、智能。不過如果有人問我 kotlin 和 java 的具體區別,那我肯定會首先描述為 命令式編程語言 和 函數式編程語言 的區別。
命令式編程語言 和 函數式編程語言 用概念描述,可以為:命令式編程語言泛指所有把修改變量的值當作最基本計算方式的語言,函數式編程語言指把一個程序的輸出定義為其輸入的數學函數的語言,純函數式編程沒有內部狀態的概念,也沒有副作用。
對兩者而言,我的體會并不深刻,所以來引用知乎的一段話:
純函數式編程語言中的變量也不是命令式編程語言中的變量,即存儲狀態的單元,而是代數中的變量,即一個值的名稱。變量的值是不可變的(immutable),也就是說不允許像命令式編程語言中那樣多次給一個變量賦值。比如說在命令式編程語言我們寫“x = x + 1”,這依賴可變狀態的事實,拿給程序員看說是對的,但拿給數學家看,卻被認為這個等式為假。
函數式語言的如條件語句,循環語句也不是命令式編程語言中的控制語句,而是函數的語法糖,比如在Scala語言中,if else不是語句而是三元運算符,是有返回值的。
關于二者的比較可以進一步查閱資料來了解,對于理解編程語言的本質和計算機的構成,很有幫助。
下面我們就來看看與 java 相比,kotlin 有哪些“高級”的語法。
函數擴展
val array: Array<Int> = arrayOf(4, 5, 6)
val array3: Array<Int> = arrayOf(7, 8, 9)
// 聲明一個函數擴展,我們需要在函數前加一個接收者類型作為前綴。上面就是為 `Array<Int>` 添加一個 swap 函數
fun Array<Int>.swap(x: Int, y: Int) {
// 在擴展函數中的 this 關鍵字對應接收者對象。
val temp: Int = this[x]
this[x] = this[y]
this[y] = temp
}
// 可以在任何 Array<Int> 實例中使用這個函數了
array.swap(1, 2)
array3.swap(0, 3)
如果用 java 來做的話,我們需要繼承父類。或者用一個方法做這個操作,需要將 array 作為參數傳遞進去,這樣一來就加大了出錯概率,也不夠自由美觀,這就是擴展帶來的好處。
空安全
導致 java 程序崩潰最多的 Exception 就是 NullPointerException 也叫 NPE,Kotlin 類型系統致力與消滅它。
在 Kotlin 類型系統中可以為空和不可為空的引用是不同的。比如,普通的 String 類型的變量不能為空:
var s: String = "activity"
s = null //編譯報錯 普通字符串類型不可為空
var t:String? = "fragment"
t = null //同?聲明的 String 可以為空
print(s.length)// 可以調用,這里的 s 永不為 null
print(t.length)// 報錯,這里的 t 可能為空
可以看到,這里在聲明一些可能為 null 的引用時,kotlin 是區分對待的,并且在調用的時候自動判斷它是否可能為 null,當可能為空的時候,直接用 .
調用,會直接報錯。
如果我們想調用,可以用條件判斷的方式:
val u = if (t != null && t.length > 0) {
print(t.length)
t.length
} else {
-1
}
這樣顯然稍顯啰嗦,kotlin 自然想到了這一點,這樣安全操作符 ?.
就出現了。
val r: Int? = t?.length
這個表達式,當 t 為 null 時,返回 null,否則返回 t.length
安全調用在鏈式調用是是很有用的。比如,如果 Bob 是一個雇員可能分配部門(也可能不分配),如果我們想獲取 Bob 的部門名作為名字的前綴,就可以這樣做:
bob?.department?.head?.name //這樣的調用鏈在任何一個屬性為空都會返回空
如果用 java 來做,那就會完全體現 java 的“又臭又長”了
Elvis 操作符
?:
Elvis 操作符表達的是,當左邊表達式為空時,會執行右邊的表達式。否則執行左邊的表達式。
val o = t?.length ?: -1
val i = t?.length ?: throw NullPointerException()
!! 表達式
val y = t!!.length
當 t 為 null 時,拋出一個 NPE,否則返回 t 的長度值。
智能轉換
is !is 表達式
fun smartCast(any: Any) {
if (any is String) {
println(any.length)// x is automatically cast to String
}
}
通過 is
關鍵字,在 if 表達式中,any 已經自動被轉換成了 String 類型。
安全轉換 as?
val s: String? = any as? String
若 any 為 null 時,顯然是不可以轉換成 String 的,這時候用 as? 安全轉換,如果失敗了,則返回 null。
字符串模板
val firstName = "Android"
val lastName = "Studio"
println("his name is $firstName $lastName")
如上所示,kotlin 可以用 $ 將一些值直接連接在字符串當中
單例模式
在 java 中,我們創建一個單例模式的對象可能是這樣子的:
public class Utils {
private Utils() {
// This utility class is not publicly instantiable
}
public static int getScore(int value) {
return 2 * value;
}
}
在 kotlin 中,就方便了很多:
object Utils {
fun getScore(value: Int): Int {
return 2 * value
}
}
Bean 對象
在 java 中創建一個 bean 對象,可能是這樣的:
public class Developer {
private String name;
private int age;
public Developer(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Developer developer = (Developer) o;
if (age != developer.age) return false;
return name != null ? name.equals(developer.name) : developer.name == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
@Override
public String toString() {
return "Developer{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
在 kotlin 中,可以使用 data 關鍵字,直接創建一個 bean 對象:
data class Developer(var name: String, var age: Int)
Ranges
kotlin 還有一些特有的屬性,比如類型的推斷啊,一級構造函數啊,等等。這些自己去擼文檔就可以了,最后一個想說的就是 kotlin 中的 Ranges 屬性。
Ranges 操作符是由 in
關鍵字實現的:
if (i in 1..10) {
println(i) // 打印 1 - 10 閉區間
}
if (x !in 1.0..3.0) println(x)
if (str in "island".."isle") println(str)
當然還有更多的用法和關鍵字,根據打印值體會:
for (i in 1..4 step 2) print(i) // prints "13"
for (i in 4 downTo 1 step 2) print(i) // prints "42"
for (i in 1.0..2.0 step 0.3) print("$i ") // prints "1.0 1.3 1.6 1.9 "
好了本文對 kotlin 一些我認為很亮眼的語法和用法就介紹完成了,下一步我打算研究下 kotlin 在快速開發 android 上,有哪些黑科技。