Kotlin第二彈

1.變量與常量

val s1 : String = "Hello"
var s2 : String = "Kotlin"
var s3 = ""

在kotlin中,val用來修飾常量计雌,初始化后就不能改變,var用來修飾變量玫霎。
例子中s1就是常量凿滤,s2就是變量妈橄。那么kotlin中的常量和java中的常量是不是一樣的呢?答案是不全一樣翁脆,java中的常量是用static final修飾眷蚓,是我們常說的編譯器常量,但是在kotlin中單單用val修飾并不是編譯器常量反番,只有用const val修飾的常量才是編譯器常量沙热。
再講一個(gè)概念,“類型推導(dǎo)”罢缸,s3變量聲明的方式就是用到了類型推導(dǎo)篙贸,雖然沒有指明類型,但是通過賦值可知s3就是String類型

2.函數(shù)

fun sum(arg1:Int,arg2:Int):Int{
    return arg1 +  arg2;
}

上面是一個(gè)最簡單的求和函數(shù)枫疆,fun是聲明函數(shù)的關(guān)鍵字爵川,sum是函數(shù)名稱,arg1和arg2是函數(shù)的Int類型的入?yún)⑾⑿ǎ祷刂档念愋褪荌nt雁芙。

fun main(args: Array<String>) {

}

這是我們的main入口函數(shù),發(fā)現(xiàn)少了什么钞螟?沒有返回值兔甘?其實(shí)是kotlin的Unit類型,相當(dāng)于java中的void類型鳞滨,當(dāng)返回值是Unit類型時(shí)可以省略洞焙,相當(dāng)于下面的寫法。

fun main(args: Array<String>):Unit{

}

除了這種簡寫方式拯啦,還可以用表達(dá)式作為返回值的簡寫方式澡匪。將例子進(jìn)行改寫

fun sum(arg1: Int,arg2: Int) = arg1 + arg2

是不是必須要有函數(shù)名呢?答案是no褒链,因?yàn)橛幸环N函數(shù)叫做匿名函數(shù)唁情。

val sum = fun(arg1:Int,arg2:Int) = arg1 + arg2

上面就是一個(gè)求和的匿名函數(shù),它被賦值給sum這個(gè)常量了甫匹,這個(gè)匿名函數(shù)的類型是(Int,Int)->Int甸鸟,那他該怎么調(diào)用呢?

println(sum(1,2))
println(sum.invoke(1,2))

第一種方式很好理解兵迅,第二種方式是什么鬼抢韭?為什么我們隨便定義的匿名函數(shù)會(huì)有一個(gè)invoke方法?我們可以打印下sum這個(gè)常量的類型

Function2<java.lang.Integer, java.lang.Integer, java.lang.Integer>

原來我們定義的匿名函數(shù)在kotlin中都能找到對(duì)應(yīng)的類型恍箭,這個(gè)Function2表示有2個(gè)Int類型的入?yún)⒑鸵粋€(gè)Int類型的出參刻恭,kotlin內(nèi)置了從Function0到Function22這個(gè)多函數(shù)類型,每個(gè)類型都有一個(gè)invoke方法扯夭。

3.lambda表達(dá)式

lambda表達(dá)式其實(shí)就是匿名函數(shù)鳍贾,只不過是進(jìn)一步的簡寫鞍匾。

    val stringArray : Array<String> = arrayOf("aa","abc","bbb","aaa","bc","ccc")
    //找出數(shù)組中帶a的元素,并打印
    stringArray.filter { it.contains("a") }.forEach { println(it) }
    println("------")
    //找出數(shù)組中元素長度是3的元素,并打印
    stringArray.filter { it.length == 3 }.forEach { println(it) }
    println("------")
    //找出數(shù)組中元素中帶小寫c的骑科,并把c裝成大寫橡淑,并打印
    stringArray.filter { it.contains("c") }.map { it.replace("c","C") }.forEach { println(it) }

上面這段代碼就是使用了lambda表達(dá)式,原本要寫循環(huán)表達(dá)式纵散,條件表達(dá)式的代碼一行代碼就搞定了梳码。filter用來過濾的,map用來批量處理的伍掀,forEach用來遍歷的掰茶。
先看filter定義

public inline fun <T> Array<out T>.filter(predicate: (T) -> Boolean): List<T> {
    return filterTo(ArrayList<T>(), predicate)
}

這是一個(gè)Array類的擴(kuò)展內(nèi)聯(lián)函數(shù),它的入?yún)⒔邮芤粋€(gè)T類型返回一個(gè)Boolean類型蜜笤,函數(shù)返回一個(gè)List T類型

map定義

public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
    return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}

這是Iterable類的擴(kuò)展內(nèi)聯(lián)函數(shù)濒蒋,它的入?yún)⒔邮芤粋€(gè)T類型,返回一個(gè)R類型,函數(shù)返回一個(gè)List R類型

foreach定義

public inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit {
    for (element in this) action(element)
}

這同樣是一個(gè)Iterable類的擴(kuò)展內(nèi)聯(lián)函數(shù)把兔,它的入?yún)⒔邮芤粋€(gè)T類型沪伙,返回一個(gè)Unit類型,函數(shù)返回一個(gè)Unit類型,所以foreach函數(shù)要放在最后面

我們嘗試自己定義一些lambda表達(dá)式:

class Student(var name:String,var age:Int){

     fun filter(action:(Student)->Boolean): Student? {
        if (action.invoke(this))
            return this
        else
            return null
    }

    fun println(action:(Student)->Unit):Unit{
        action(this)
    }
}

val s : Student = Student("aaa",11)
s.filter { it.name.startsWith("a") }?.filter { it.age > 10 }?.println { println("${it.name}-${it.age}") }

我們自定義了Stdent類县好,并定義了filter和println兩個(gè)函數(shù)围橡,filter函數(shù)入?yún)⒌膌ambda表達(dá)式傳入一個(gè)Student,返回一個(gè)Boolean缕贡,函數(shù)返回Student?類型翁授。println函數(shù)入?yún)⒌膌ambda表達(dá)式傳入一個(gè)Student,返回一個(gè)Boolean晾咪,函數(shù)返回Unit收擦。這樣我們也能用一行代碼對(duì)student對(duì)象進(jìn)行過濾打印,過濾規(guī)則和打印格式都通過lambda表達(dá)式傳入谍倦。

關(guān)于lambda表達(dá)式后面會(huì)經(jīng)常碰到塞赂,這里就先簡單介紹下。

4.類的成員和方法

class ABC(var a:String,b:Int){
    var c : Int = 0
        get() {
            println("get c")
            return field
        }
        set(value) {
            println("set c")
            field = value
        }
}

上面這個(gè)ABC類昼蛀,a和c是類的成員宴猾,b只是局部變量,只能在類內(nèi)部使用.kotlin中類的成員變量會(huì)默認(rèn)生成get/set方法曹洽,當(dāng)然也可以重寫鳍置,但是聲明在構(gòu)造器內(nèi)部的成員變量只能使用默認(rèn)的set/get方法。

關(guān)于類的成員變量初始化的一些問題送淆。

class AAA(var a:String){
    var b : Int = 0
    var c : String? = null
    lateinit var d : String
    val e : IntArray by lazy { intArrayOf(1,2) }
}

上面這個(gè)AAA類中有5個(gè)成員變量,分別代表5種不同的初始化方式怕轿,a是在構(gòu)造器中聲明偷崩,要使用這個(gè)類必須要初始化a辟拷,b是Int類型,初始化賦值為了0阐斜,c被聲明成了可空的String類型衫冻,并賦值為null,這種方式會(huì)為后面使用帶來不變谒出,d使用了lateinit關(guān)鍵字隅俘,作用是可以延遲初始化,但是使用前不初始化會(huì)崩潰笤喳,e使用了by lazy的懶加載方式

5.運(yùn)算符重載

在java中并沒有運(yùn)算符重載的概念为居,kotlin中的運(yùn)算符重載跟c++很相似,我們會(huì)自定義一個(gè)類杀狡,實(shí)現(xiàn)這個(gè)類的加減乘除的運(yùn)算蒙畴。

class BBB(var i :Int){
    operator fun plus(other:BBB):BBB{
        return BBB(this.i + other.i)
    }

    operator fun minus(other: BBB):BBB{
        return BBB(this.i-other.i)
    }

    operator fun times(other: BBB):BBB{
        return BBB(this.i*other.i)
    }

    operator fun div(other: BBB):BBB{
        return BBB(this.i/other.i)
    }

    override fun toString(): String {
        return "$i"
    }
}

自定義了BBB這個(gè)類,它有i這個(gè)Int類型的成員變量呜象,BBB這個(gè)類定義了加減乘除四種運(yùn)算符膳凝,實(shí)際上就是內(nèi)部i這個(gè)成員變量進(jìn)行運(yùn)算。例子有點(diǎn)脫褲子放屁恭陡,但是基本能說明運(yùn)算符重載的使用方式蹬音。

fun main(args: Array<String>) {
    val a = BBB(1)
    val b = BBB(2)
    val c = (a + b) * b / a
    println(c)
}

打印是6

6.條件表達(dá)式

條件語句和條件表達(dá)式的區(qū)別是條件語句是來控制流程的,而條件表達(dá)式可以被用來復(fù)制休玩。本節(jié)主要討論if和when的使用著淆。
if作為條件語句的方式非常簡單

var a : String?
    if (args[0].equals("-name")){
        a = args[1]
    }else{
        a = null
    }

這就是if條件語句。

var a : String? =
    if (args[0].equals("-name")){
        args[1]
    }else{
        null
    }

這就是if條件表達(dá)式.

kotlin中的when是java的switch的加強(qiáng)版哥捕,switch能實(shí)現(xiàn)的功能when都能實(shí)現(xiàn)牧抽,switch不能實(shí)現(xiàn)的when也能實(shí)現(xiàn),好吊的遥赚!

when(args[0]){
        is String -> "String"
        "-name" -> args[1]
        in arrayOf("-java","-kotlin") -> args[2].toInt()
        else -> null
    }

不說了扬舒,自己體會(huì)吧。同樣也可以作為表達(dá)式賦值給變量

var a : Any? =
    when(args[0]){
        is String -> "String"
        "-name" -> args[1]
        in arrayOf("-java","-kotlin") -> args[2].toInt()
        else -> null
    }

7.循環(huán)語句

var array = intArrayOf(1,2,3,4,5,6,7,8)
    for (i in array){
        println("$i")
    }

一般情況凫佛,我們都是用for...in語句來迭代對(duì)象讲坎,比如array,list等愧薛。但是有沒有想過為什么這些對(duì)象可以使用for...語句呢晨炕?這是因?yàn)檫@些迭代對(duì)象都有iterator()方法,他會(huì)返回一個(gè)對(duì)應(yīng)的迭代器對(duì)象毫炉,循環(huán)其實(shí)是在遍歷這個(gè)迭代器瓮栗?那么我們自己試試看,創(chuàng)建一個(gè)可以被迭代的對(duì)象。

class MyIntArray{
    private val list : MutableList<Int> = mutableListOf()

    fun add(i: Int){
        list.add(i)
    }

    fun remove(i: Int){
        list.remove(i)
    }

    operator fun iterator():MyIterator{
        return MyIterator(list.iterator())
    }
}

MyIntArray這個(gè)類內(nèi)部有一個(gè)list對(duì)象來存儲(chǔ)數(shù)據(jù)费奸,同樣有一個(gè)iterator方法返回一個(gè)MyIterator迭代器弥激。

class MyIterator(var iterator: Iterator<Int>){

    operator fun next():Int{
        return iterator.next()
    }

    operator fun hasNext():Boolean{
        return iterator.hasNext()
    }

}

這就是MyIterator的實(shí)現(xiàn),其實(shí)就是使用的是外部傳入list的迭代器愿阐。

var array2 = MyIntArray()
    array2.add(10)
    array2.add(20)
    array2.add(30)
    array2.add(40)
    for (i in array2){
        println("$i")
    }

這是我們的測試代碼微服,編譯通過,輸出正常缨历,原來for...in遍歷的就是迭代器以蕴,只要循環(huán)的對(duì)象有iterator方法,并返回一個(gè)正常的迭代器就能使用for...in循環(huán)辛孵。

除了for...in語句丛肮,還有while,do...while語句一樣可以用于循環(huán)觉吭,對(duì)于array腾供,list等對(duì)象,系統(tǒng)還定義了foreach這個(gè)函數(shù)用于lambda表達(dá)式去循環(huán)鲜滩。

8.異常捕獲

var s : String = ""
    try {
        s.toInt()
    }catch (e:Exception){
        e.printStackTrace()
    }finally {
        println("end")
    }

kotlin中的異常捕獲跟java沒什么區(qū)別伴鳖,連關(guān)鍵字都一樣。但是同樣可以作為表達(dá)式為變量賦值徙硅。類似這樣...

var s : String = ""
    var i = try {
        s.toInt()
    }catch (e:Exception){
        0
    }finally {
        println("end")
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末榜聂,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子嗓蘑,更是在濱河造成了極大的恐慌须肆,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件桩皿,死亡現(xiàn)場離奇詭異豌汇,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)泄隔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門拒贱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人佛嬉,你說我怎么就攤上這事逻澳。” “怎么了暖呕?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵斜做,是天一觀的道長。 經(jīng)常有香客問我湾揽,道長瓤逼,這世上最難降的妖魔是什么笼吟? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮抛姑,結(jié)果婚禮上赞厕,老公的妹妹穿的比我還像新娘艳狐。我一直安慰自己定硝,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布毫目。 她就那樣靜靜地躺著蔬啡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪镀虐。 梳的紋絲不亂的頭發(fā)上箱蟆,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音刮便,去河邊找鬼空猜。 笑死,一個(gè)胖子當(dāng)著我的面吹牛恨旱,可吹牛的內(nèi)容都是我干的辈毯。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼搜贤,長吁一口氣:“原來是場噩夢啊……” “哼谆沃!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起仪芒,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤唁影,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后掂名,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體据沈,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年饺蔑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了锌介。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡膀钠,死狀恐怖掏湾,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情肿嘲,我是刑警寧澤融击,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站雳窟,受9級(jí)特大地震影響尊浪,放射性物質(zhì)發(fā)生泄漏匣屡。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一拇涤、第九天 我趴在偏房一處隱蔽的房頂上張望捣作。 院中可真熱鬧,春花似錦鹅士、人聲如沸券躁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽也拜。三九已至,卻和暖如春趾痘,著一層夾襖步出監(jiān)牢的瞬間慢哈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來泰國打工永票, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留卵贱,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓侣集,卻偏偏與公主長得像键俱,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子肚吏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

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