Kotlin 語法上的一些亮眼操作

Kotlin 語法上的一些亮眼操作

本文原創,轉載請注明出處。
歡迎關注我的 簡書 ,關注我的專題 Android Class 我會長期堅持為大家收錄簡書上高質量的 Android 相關博文。

Kotlin 初體驗

寫在前面:
上上周我們創建了第一個 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 上,有哪些黑科技。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,763評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,238評論 3 428
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,823評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,604評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,339評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,713評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,712評論 3 445
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,893評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,448評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,201評論 3 357
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,397評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,944評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,631評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,033評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,321評論 1 293
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,128評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,347評論 2 377

推薦閱讀更多精彩內容