kotlin 入門教程

kotlin是 JetBrains 在 2010 年推出的基于 JVM 的新編程語言。開發(fā)者稱北发,設(shè)計它的目的是避免 Java 語言編程中的一些難題。比如:在 Kotlin 中類型系統(tǒng)控制了空指針引用脊框,可以有效避免 Java 中常見的NullPointException。
作為一個跨平臺的語言,Kotlin 可以工作于任何 Java 的工作環(huán)境:服務(wù)器端的應(yīng)用昂利,移動應(yīng)用(Android版)祥国,桌面應(yīng)用程序。

Kotlin的優(yōu)勢

相比于 Java碳抄,Kotlin 有著更好的語法結(jié)構(gòu)愉老,安全性和開發(fā)工具支持。Kotlin 中沒有基礎(chǔ)類型剖效,數(shù)組是定長的嫉入,泛型是安全的,即便運(yùn)行時也是安全的璧尸。此外咒林,該語言支持閉包,還可通過內(nèi)聯(lián)進(jìn)行優(yōu)化爷光。不過垫竞,它不支持檢查異常(Checked Exceptions),許多語言設(shè)計者認(rèn)為這是它的瑕疵蛀序。不論如何欢瞪,重要的是 Java 和 Kotlin 之間的互操作性:Kotlin 可以調(diào)用 Java,反之亦可徐裸。

變量

fun main(args: Array<String>) {
    var quantity = 5
    val price: Double = 20.3
    val name: String = "大米"

    println("單價:$price")
    println("數(shù)量:$quantity")
    println("產(chǎn)品:$name 總計:${quantity * price}")
}   

in關(guān)鍵字的使用

//如果存在于區(qū)間(1,Y-1)遣鼓,則打印OK
if (x in 1..y-1) 
  print("OK")

//如果x不存在于array中,則輸出Out
if (x !in 0..array.lastIndex) 
  print("Out")

//打印1到5
for (x in 1..5) 
  print(x)

//遍歷集合(類似于Java中的for(String name : names))
for (name in names)
  println(name)

//如果names集合中包含text對象則打印yes
if (text in names)
  print("yes")

when表達(dá)式

類似于 Java 中的 switch重贺,但是 Kotlin 更加智能骑祟,可以自動判斷參數(shù)的類型并轉(zhuǎn)換為響應(yīng)的匹配值。

fun cases(obj: Any) { 
  when (obj) {
    1       -> print("第一項(xiàng)")
    "hello" -> print("這個是字符串hello")
    is Long -> print("這是一個Long類型數(shù)據(jù)")
    !is String -> print("這不是String類型的數(shù)據(jù)")
    else    -> print("else類似于Java中的default")
  }
}

智能類型推測

判斷一個對象是否為一個類的實(shí)例气笙,可以使用is關(guān)鍵字
與 Java 中的instanceof關(guān)鍵字類似次企,但在 Kotlin 中如果已經(jīng)確定了一個對象的類型,可以在接下來的代碼塊中直接作為這個確定類型使用健民。

fun getStringLength(obj: Any): Int? {
  if (obj is String) {
    // 做過類型判斷以后抒巢,obj會被系統(tǒng)自動轉(zhuǎn)換為String類型
    return obj.length 
  }

  //同時還可以使用!is,來取反
  if (obj !is String){
  }

  // 代碼塊外部的obj仍然是Any類型的引用
  return null
}

空值檢測

Kotlin 是空指針安全的秉犹,也就意味著你不會再看到那惱人的空指針異常蛉谜。
例如這句代碼 println(files?.size)稚晚,只會在files不為空時執(zhí)行。
以及型诚,你可以這樣寫

//當(dāng)data不為空的時候客燕,執(zhí)行語句塊
data?.let{
    //... 
}

//相反的,以下代碼當(dāng)data為空時才會執(zhí)行
data?:let{
    //...
}

函數(shù)

函數(shù)的聲明

函數(shù)使用關(guān)鍵字fun聲明狰贯,如下代碼創(chuàng)建了一個名為say()的函數(shù)也搓,它接受一個String類型的參數(shù),并返回一個String類型的值

fun say(str: String): String {
    return str
}

同時涵紊,在 Kotlin 中傍妒,如果像這種簡單的函數(shù),可以簡寫為

fun say(str: String): String = str

如果是返回Int類型摸柄,那么你甚至連返回類型都可以不寫

fun getIntValue(value: Int) = value

函數(shù)的默認(rèn)參數(shù)

你也可以使用默認(rèn)參數(shù)來實(shí)現(xiàn)重載類似的功能

fun say(str: String = "hello"): String = str

這時候你可以調(diào)用say()颤练,來得到默認(rèn)的字符串 "hello",也可以自己傳入?yún)?shù)say("world")來得到傳入?yún)?shù)值驱负。
有時參數(shù)非常多的時候嗦玖,也可以使用多行參數(shù)的寫法,它們是相同的

fun say(firstName: String = "Tao",
        lastName: String = "Zhang"){
}

變參函數(shù)

同 Java 的變長參數(shù)一樣跃脊,Kotlin 也支持變長參數(shù)

//在Java中宇挫,我們這么表示一個變長函數(shù)
public boolean hasEmpty(String... strArray){
    for (String str : strArray){
        if ("".equals(str) || str == null)
            return true;
    }
    return false;
}

//在Kotlin中,使用關(guān)鍵字vararg來表示
fun hasEmpty(vararg strArray: String?): Boolean{
    for (str in strArray){
        if ("".equals(str) || str == null)
            return true 
    }
    return false
}

擴(kuò)展函數(shù)

你可以給父類添加一個方法酪术,這個方法將可以在所有子類中使用器瘪。例如,在 Android 開發(fā)中绘雁,我們常常使用這樣的擴(kuò)展函數(shù):

fun Activity.toast(message: CharSequence, duration: Int = Toast.LENGTH_SHORT) {
    Toast.makeText(this, message, duration).show()
}

將函數(shù)作為參數(shù)

Kotlin 中娱局,可以將一個函數(shù)作為參數(shù)傳遞給另一個函數(shù)

fun invokeModule(webview: View?, cmd: String, parameters: String, 
callback: String,
callbackFunction: (String, String) -> Unit):String?

上面的代碼中,我們傳入了一個(String, String) -> Unit的參數(shù)

kotlin類特性

與 Java 相同咧七,Kotlin 聲明類的關(guān)鍵字是class。類聲明由類名任斋、類頭和類體構(gòu)成继阻。
其中類頭和類體都是可選的; 如果一個類沒有類體,那么花括號也是可以省略的废酷。

構(gòu)造函數(shù)

Kotlin 的構(gòu)造函數(shù)可以寫在類頭中瘟檩,跟在類名后面,如果有注解還需要加上關(guān)鍵字constructor澈蟆。這種寫法聲明的構(gòu)造函數(shù)墨辛,我們稱之為主構(gòu)造函數(shù)。例如下面我們?yōu)镻erson創(chuàng)建帶一個String類型參數(shù)的構(gòu)造函數(shù)趴俘。

class Person(private val name: String) {
    fun sayHello() {
        println("hello $name")
    }
}

在主構(gòu)造函數(shù)中不能有任何代碼實(shí)現(xiàn)睹簇,如果有額外的代碼需要在構(gòu)造方法中執(zhí)行奏赘,你需要放到init代碼塊中執(zhí)行。

class Person(private var name: String) {
    
    init {
        name = "Zhang Tao"
    }

    internal fun sayHello() {
        println("hello $name")
    }
}

protected 在 “top-level” 中不可以使用太惠,即不能修飾包級別的方法或者屬性等
private 聲明在包含聲明的源文件中可見
internal 聲明磨淌,在同一模塊中的任何地方可見

次構(gòu)造函數(shù)

class Person(private var name: String) {

    private var description: String? = null
    
    init {
        name = "Zhang Tao"
    }

    constructor(name: String, description: String) : this(name) {
        this.description = description
    }
    
    internal fun sayHello() {
        println("hello $name")
    }
}

枚舉類

enum class Programer {
    JAVA, KOTLIN, C, CPP, ANDROID;
}

密封類

sealed class BaseClass {

    class Test1 : BaseClass() {
        override fun test() {
            println("Test1實(shí)例")
        }

    }
    class Test2 : BaseClass() {
        override fun test() {
            println("Test2實(shí)例")
        }
    }
    object Test3 : BaseClass() {
        override fun test() {
            println("Test3實(shí)例")
        }
    }
    open fun test() {
        println("BaseClass實(shí)例")
    }
}

sealed 修飾的類稱為密封類,用來表示受限的類層次結(jié)構(gòu)凿渊。例如當(dāng)一個值為有限集中的 類型梁只、而不能有任何其他類型時。在某種意義上,他們是枚舉類的擴(kuò)展:枚舉類型的值集合也是受限的埃脏,但每個枚舉常量只存在一個實(shí)例,而密封類的一個子類可以有可包含狀態(tài)的多個實(shí)例搪锣。

data 數(shù)據(jù)類

data 修飾的類稱之為數(shù)據(jù)類。它通常用在我們寫的一些 POJO 類上彩掐。當(dāng) data 修飾后构舟,會自動將所有成員用operator聲明,即為這些成員生成類似 Java 的 getter/setter 方法佩谷。
編譯器自動從主構(gòu)造器中的屬性導(dǎo)入下面這些成員函數(shù):

  • equals()/hashCode()
  • toString()(形式為User(name=John,age=42))
  • componentN()函數(shù)對應(yīng)著聲明的屬性順序
  • copy()函數(shù)
data class User(val name: String, val age: Int)

伴生對象

由于 Kotlin 沒有靜態(tài)方法旁壮。在大多數(shù)情況下,官方建議是簡單地使用 包級 函數(shù)谐檀。如果你需要寫一個可以無需用一個類的實(shí)例來調(diào)用抡谐、但需要訪問類內(nèi)部的函數(shù)(例如,工廠方法或單利),你可以把它寫成一個用 companion修飾的對象內(nèi)的方法。我們稱companion修飾的對象為伴生對象桐猬。

class StringUtils {
    companion object {
       fun isEmpty(str: String): Boolean {
            return "" == str
        }
    }
}

單例類的設(shè)計

class Single private constructor() {
    companion object {
        fun get():Single{
            return Holder.instance
        }
    }

    private object Holder {
        val instance = Single()
    }
}

通過關(guān)鍵字object

object Single{
}

委托

Kotlin 直接支持委托模式麦撵,更加優(yōu)雅,簡潔溃肪。Kotlin 通過關(guān)鍵字 by 實(shí)現(xiàn)委托免胃。有點(diǎn)像java的動態(tài)代理。

interface Animal{
    fun bark()
}

class Dog :Animal {
    override fun bark() {
        println("Wang Wang")
    }
}

class Cat(animal: Animal) : Animal by animal {
}

fun main(args: Array<String>) {
   Cat(Dog()).bark()
}

這樣惫撰,我們就很成功的讓一只貓的叫聲用狗去代理掉了羔沙,于是上面的main方法執(zhí)行完后就變成了 Wang Wang。

屬性的委托

import kotlin.reflect.KProperty
// 定義包含屬性委托的類
class Example {
    var p: String by Delegate()
}

// 委托的類
class Delegate {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return "$thisRef, 這里委托了 ${property.name} 屬性"
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        println("$thisRef 的 ${property.name} 屬性賦值為 $value")
    }
}
fun main(args: Array<String>) {
    val e = Example()
    println(e.p)     // 訪問該屬性厨钻,調(diào)用 getValue() 函數(shù)

    e.p = "Runoob"   // 調(diào)用 setValue() 函數(shù)
    println(e.p)
}

輸出結(jié)果:
Example@433c675d, 這里委托了 p 屬性
Example@433c675d 的 p 屬性賦值為 Runoob
Example@433c675d, 這里委托了 p 屬性

可觀察屬性 Observable

@[Kotlin 的標(biāo)準(zhǔn)庫中已經(jīng)內(nèi)置了很多工廠方法來實(shí)現(xiàn)屬性的委托扼雏。]

import kotlin.properties.Delegates

class User {
    var name: String by Delegates.observable("初始值") {
        prop, old, new ->
        println("舊值:$old -> 新值:$new")
    }
}

fun main(args: Array<String>) {
    val user = User()
    user.name = "第一次賦值"
    user.name = "第二次賦值"
}

執(zhí)行輸出結(jié)果:
舊值:初始值 -> 新值:第一次賦值
舊值:第一次賦值 -> 新值:第二次賦值

閉包

一段程序代碼通常由常量、變量和表達(dá)式組成夯膀,然后使用一對花括號“{}”來表示閉合诗充,并包裹著這些代碼,由這對花括號包裹著的代碼塊就是一個閉包诱建。其實(shí)在簽名我們也介紹了全局和嵌套函數(shù)就是一種特殊的閉包蝴蜓。這里,我們總結(jié)了一下,Kotlin語言中有三種閉包形式:全局函數(shù)茎匠、自嵌套函數(shù)格仲、匿名函數(shù)體。

fun main(args: Array<String>) {
    // 執(zhí)行test閉包的內(nèi)容
    test
}

// 定義一個比較測試閉包
val test = if (5 > 3) {
    println("yes")
} else {
    println("no")
}

閉包的用途汽抚?

/**
 * 計數(shù)統(tǒng)計
 */
fun justCount():() -> Unit{
    var count = 0
    return {
        println(count++)
    }
}


fun main(args: Array<String>) {

    val count = justCount()
    count()  // 輸出結(jié)果:0
    count()  // 輸出結(jié)果:1
    count()  // 輸出結(jié)果:2
}

自執(zhí)行閉包

自執(zhí)行閉包就是在定義閉包的同時直接執(zhí)行閉包抓狭,一般用于初始化上下文環(huán)境。 例如:

{ x: Int, y: Int ->
    println("${x + y}")
}(1, 3)

Lambda表達(dá)式

val printMsg = { msg: String -> 
    println(msg) 
}

fun main(args: Array<String>) {
  printMsg.invoke("hello")
}

帶接收者的with,apply

var s=with("abc"){
        this.plus("d")
    }
    println(s)

apply始終返回座位實(shí)參傳遞給它的對象

 var r="abc".apply {
        this.plus("d")
    }

    println(r)

let表達(dá)式一般結(jié)合類型安全檢查使用

var x: String? = null
    x?.let {
        println("x=${it}")
    }

集合和泛型

集合

所有類聲明的泛型尖括號里面如果加入了 out 關(guān)鍵字造烁,則說明這個類的對象是只讀的否过,例如他只有:get()、size()等方法惭蟋,而沒有 set()苗桂、remove()等方法。
相反的告组,如果沒有加 out 關(guān)鍵字煤伟,或者換一種記法:如果開頭是 MutableXXX 那就是一個跟 Java 中用法一致的集合類。

open class A
open class B : A()
open class C : B()

class TypeArray<in A> {
    
    //in 修飾了 A木缝,表示 A 是可以作為參數(shù)的便锨。
    fun getValue(a: A): Int? {
        return a?.hashCode()
    }
    
    //這段代碼是非法的,因?yàn)锳 不能被返回
    fun getA(a: A): A? {
        return a
    }
}

集合的初始化

在 Kotlin 中我碟,集合類一般不使用構(gòu)造方法去初始化放案,而是使用同一的入口方法,例如初始化一個 MutableList矫俺,我們使用的是如下代碼:

val mutableList = mutableListOf(0, 1, 2, 3)

類似的初始化集合對象的方法還有

//創(chuàng)建一個 List<> 對象
var list = listOf(0, 1, 2)

//創(chuàng)建一個 Set<> 對象
val ss = setOf(1, 2, 4)

操作符

比如說輸出wifi密碼duowan123
java實(shí)現(xiàn):

final String[] a = new String[]{"a", "1", "u", "2", "o", "n", "3", "d", "w"};
final Integer[] indexs = new Integer[]{7, 10, 2, 4, 11, 8, 0, 5, 1, 3, 15, 6};

常用操作符

Kotlin 的操作符跟 RxJava 基本一致吱殉,不需要額外記憶。

下標(biāo)操作類
  • contains —— 判斷是否有指定元素
  • elementAt —— 返回對應(yīng)的元素厘托,越界會拋- IndexOutOfBoundsException
  • firstOrNull —— 返回符合條件的第一個元素友雳,沒有 返回null
  • lastOrNull —— 返回符合條件的最后一個元素,沒有 返回null
  • indexOf —— 返回指定元素的下標(biāo)铅匹,沒有 返回-1
  • singleOrNull —— 返回符合條件的單個元素押赊,如有沒有符合或超過一個,返回null
判斷類
  • any —— 判斷集合中 是否有滿足條件 的元素
  • all —— 判斷集合中的元素 是否都滿足條件
  • none —— 判斷集合中是否 都不滿足條件包斑,是則返回true
  • count —— 查詢集合中 滿足條件 的 元素個數(shù)
  • reduce —— 從 第一項(xiàng)到最后一項(xiàng)進(jìn)行累計
過濾類
  • filter —— 過濾 掉所有 滿足條件 的元素
  • filterNot —— 過濾所有不滿足條件的元素
  • filterNotNull —— 過濾NULL
  • take —— 返回前 n 個元素
轉(zhuǎn)換類
  • map —— 轉(zhuǎn)換成另一個集合(與上面我們實(shí)現(xiàn)的 convert 方法作用一樣);
  • mapIndexed —— 除了轉(zhuǎn)換成另一個集合考杉,還可以拿到Index(下標(biāo));
  • mapNotNull —— 執(zhí)行轉(zhuǎn)換前過濾掉 為 NULL 的元素
  • flatMap —— 自定義邏輯合并兩個集合;
  • groupBy —— 按照某個條件分組舰始,返回Map;
排序類
  • reversed —— 反序
  • sorted —— 升序
  • sortedBy —— 自定義排序
  • sortedDescending —— 降序

用于 Android 開發(fā)的工具

Kotlin 團(tuán)隊(duì)為 Android 開發(fā)提供了一套超越標(biāo)準(zhǔn)語言功能的工具:

  • Kotlin Android 擴(kuò)展是一個編譯器擴(kuò)展咽袜, 可以讓你擺脫代碼中的 findViewById() 調(diào)用丸卷,并將其替換為合成的編譯器生成的屬性。
  • Anko 是一個提供圍繞 Android API 的 Kotlin 友好的包裝器的庫 询刹,以及一個可以用 Kotlin 代碼替換布局 .xml 文件的 DSL谜嫉。
  • Android KTX 一個 Kotlin 代碼的擴(kuò)展庫萎坷,比較常用的一些代碼塊,進(jìn)行封裝沐兰,然后在這個基礎(chǔ)上哆档,提供更良好的 API,供開發(fā)者使用住闯。
    參考鏈接
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末瓜浸,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子比原,更是在濱河造成了極大的恐慌插佛,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件量窘,死亡現(xiàn)場離奇詭異雇寇,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蚌铜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門锨侯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人冬殃,你說我怎么就攤上這事囚痴。” “怎么了造壮?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵渡讼,是天一觀的道長。 經(jīng)常有香客問我耳璧,道長成箫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任旨枯,我火速辦了婚禮蹬昌,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘攀隔。我一直安慰自己皂贩,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布昆汹。 她就那樣靜靜地躺著明刷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪满粗。 梳的紋絲不亂的頭發(fā)上辈末,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼挤聘。 笑死轰枝,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的组去。 我是一名探鬼主播鞍陨,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼从隆!你這毒婦竟也來了诚撵?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤广料,失蹤者是張志新(化名)和其女友劉穎砾脑,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體艾杏,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡韧衣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了购桑。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片畅铭。...
    茶點(diǎn)故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖勃蜘,靈堂內(nèi)的尸體忽然破棺而出硕噩,到底是詐尸還是另有隱情,我是刑警寧澤缭贡,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布炉擅,位于F島的核電站,受9級特大地震影響阳惹,放射性物質(zhì)發(fā)生泄漏谍失。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一莹汤、第九天 我趴在偏房一處隱蔽的房頂上張望快鱼。 院中可真熱鬧,春花似錦纲岭、人聲如沸抹竹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽窃判。三九已至,卻和暖如春喇闸,著一層夾襖步出監(jiān)牢的瞬間袄琳,已是汗流浹背窿凤。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留跨蟹,地道東北人。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓橘沥,卻偏偏與公主長得像窗轩,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子座咆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容