Kotlin總結(jié)分享

集合創(chuàng)建

像創(chuàng)建一個(gè)數(shù)組一樣初始化一個(gè)含有默認(rèn)值的集合癣猾。避免了先創(chuàng)建,再賦值,這一點(diǎn)在java中是做不到的

  • 普通集合
//Java
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);

//Kotlin
val list = listOf(1,2,3)
  • 鍵值對(duì)集合
val map = mapOf(1 to "one",2 to "two",3 to "three")

Kotlin 中雙冒號(hào) :: 使用

Kotlin 中 雙冒號(hào)操作符 表示把一個(gè)方法當(dāng)做一個(gè)參數(shù)晚唇,傳遞到另一個(gè)方法中進(jìn)行使用,通俗的來講就是引用一個(gè)方法杨何。eg:

fun main(args: Array<String>) {
    println(lock("param1", "param2", ::getResult))
}

/**
 * @param str1 參數(shù)1
 * @param str2 參數(shù)2
 */
fun getResult(str1: String, str2: String): String = "result is {$str1 , $str2}"

/**
 * @param p1 參數(shù)1
 * @param p2 參數(shù)2
 * @param method 方法名稱
 */
fun lock(p1: String, p2: String, method: (str1: String, str2: String) -> String): String {
    return method(p1, p2)
}

這里需要注意的是酱塔,lock 函數(shù) 的第三個(gè)參數(shù)傳入 method 時(shí),要確定參數(shù)個(gè)數(shù)危虱、類型羊娃、返回值都和其形參一致。

輸出結(jié)果:

result is {param1 , param2}

需要調(diào)用其他 Class 中的某一個(gè)方法時(shí):

fun main(args: Array<String>) {
    var d = Test()
    println(lock("param1", "param2", d::getResult))
}

Class 的內(nèi)部方法時(shí)調(diào)動(dòng)方式為:

class Test1 {
    fun isOdd(x: Int) = x % 2 != 0

    fun test() {
        var list = listOf(1, 2, 3, 4, 5)
        println(list.filter(this::isOdd))
    }
}

一般情況埃跷,調(diào)用當(dāng)前類的方法 this 都是可省略的

集合中的高階函數(shù)

map

map通常用于集合的映射蕊玷,例如:

val oldList = listOf(1, 2, 3, 4, 5)
val newList = ArrayList<Int>()

println("集合映射--傳統(tǒng)寫法")
oldList.forEach {
    val newElement = it * 2 + 3
    newList.add(newElement)
}

println("集合映射--Kotlin寫法邮利,使用map")
val newList1 = oldList.map {
    it * 2 + 3
}
flatMap

flatMap通常用于扁平化集合,就是把集合的集合扁平化成集合垃帅,例如:

println("扁平化集合")
val list = listOf(
        1..20,
        2..5,
        3..4
)
val newList3 = list.flatMap {
    it
}
newList3.forEach(::println)

flatMap結(jié)合map進(jìn)行變換延届,例如:

println("扁平化集合+變換")
val newList4 = list.flatMap {
    it.map {
        "NO.$it"
    }
}
newList4.forEach(::println)
reduce

reduce通常用于求和,例如:

println("求和")
var sum = oldList.reduce { acc, i -> acc + i }
println(sum)

利用reduce求階乘:

var res2 = (1..5).map(::factorial)
println(res2)

//求n的階乘:n!=1×2×3×...×n
fun factorial(n: Int): Int {
    if (n == 0) {
        return 1
    } else {
        return (1..n).reduce { acc, i -> acc * i }
    }
}

fold

fold通常用于求和并且加上一個(gè)初始值贸诚,例如:

sum = (1..5).fold(5) { acc, i -> acc + i }
println(sum)

fold還可以進(jìn)行變換方庭,進(jìn)行字符串的連接:

var res = (1..5).fold(StringBuilder()) { acc, i ->
    acc.append(i).append(",")
}
println(res)

//也可以這樣寫
var res1 = (1..5).joinToString(",")
println(res1)

filter

filter用于過濾,如果傳入的表達(dá)式的值為true的時(shí)候就保留:

//表達(dá)式為true的時(shí)候保留元素
val newList5 = oldList.filter {
    it == 2 || it == 4
}
println(newList5)

包括filterIndexed 的用法也很類似:

oldList.filterIndexed { index, i ->
    index == 1
}

中綴函數(shù)

這val map = mapOf(1 to "one", 2 to "two")里的to就是一個(gè)infix function酱固。其源碼實(shí)現(xiàn):
public infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)

普通函數(shù)的使用方法都是通過對(duì)象.函數(shù)名實(shí)現(xiàn)的械念,在kotlin中為了方便我們的使用引入了另外一種函數(shù)類型——中綴函數(shù)。這種函數(shù)通過infix關(guān)鍵字定義运悲,有且只有一個(gè)參數(shù)龄减,通過放在對(duì)象之后直接使用,在函數(shù)名之后緊接著的是該函數(shù)傳入的值班眯。中間無需.或()等特殊符號(hào)鏈接希停。

兩個(gè)關(guān)鍵要素:

  • 1.使用infix在fun前修飾
  • 2.只能有一個(gè)參數(shù)
//中綴函數(shù)
infix fun String.getChar(position: Int) = this.get(position)
val s = "Hello world"
val c = s getChar 1
//普通函數(shù)
fun String.getChar(position: Int) = this.get(position)
val s = "Hello world"
val c = s.getChar(1)

字符串比較

//普通使用字符串對(duì)比調(diào)用StringUtils.equals(strA, strB)
fun main(args: Array<string>) {
    val strA = "A"
    val strB = "B"
    if (StringUtils.equals(strA, strB)) {//這里對(duì)比字符串是了apache中的StringUtils
        println("str is the same")
    } else {
        println("str is the different")
    }
}
 
//利用中綴調(diào)用sameAs對(duì)比兩個(gè)字符串
fun main(args: Array<string>) {
    val strA = "A"
    val strB = "B"
    if (strA sameAs strB) {//中綴調(diào)用 sameAs
        println("str is the same")
    } else {
        println("str is the different")
    }
}

判斷一個(gè)元素是否在集合中

//普通調(diào)用集合contains方法判斷元素是否在集合中
fun main(args: Array<string>) {
    val list = listOf(1, 3, 5, 7, 9)
    val element = 2
    if (list.contains(element)) {
        println("element: $element is into list")
    } else {
        println("element: $element is not into list")
    }
}
 
//利用中綴調(diào)用into判斷元素是否在集合中
fun main(args: Array<string>) {
    val list = listOf(1, 3, 5, 7, 9)
    val element = 2
    if (element into list) {//中綴調(diào)用,這樣的寫法鳖敷,會(huì)更加接近我們自然語言的表達(dá)脖苏,更容易理解
        println("element: $element is into list")
    } else {
        println("element: $element is not into list")
    }
}

頂層函數(shù)和屬性

java ----- 萬物皆為對(duì)象
kotlin ----- 打破了這種思維定式

Java中本著”萬物皆為對(duì)象“的設(shè)計(jì)原理,所有的函數(shù)和屬性都是依附于class來實(shí)現(xiàn)的定踱,因此很多獨(dú)立的工具方法我們不得不為其創(chuàng)建一個(gè)類來進(jìn)行管理棍潘,也就是我們常說的工具類。這樣的實(shí)現(xiàn)其實(shí)是有些奇怪的崖媚,但是在Kotlin編程里為我們解決了這樣的煩惱亦歉。

- 頂層函數(shù)

我們可以在任何一個(gè)普通的.kt文件中聲明我們想要的函數(shù),并且我們不需要為該函數(shù)創(chuàng)建包裝類畅哑,該函數(shù)就是函數(shù)本身肴楷,就像C語言一樣,以函數(shù)為基本單位而不是類荠呐。

package com.dy.comm.kotlinapplication

fun log(message: String?) {
    Log.i("TAG", message)
}

最終會(huì)編譯成Java字節(jié)碼赛蔫,所以實(shí)現(xiàn)代碼其實(shí)是這樣的:

package com.dy.comm.kotlinapplication

public class XXX() {
    public static void log(String message) {Log.i("TAG", message)}
}

優(yōu)點(diǎn):方便了編寫代碼

- 頂層屬性

和頂層函數(shù)類似,可以用于存儲(chǔ)一些固定常用量泥张,eg:URL等呵恢。

Kotlin中的解構(gòu)聲明

把一個(gè)對(duì)象的成員解構(gòu)成多個(gè)變量,稱為解構(gòu)聲明

componentN是操作符(類似加減乘除的運(yùn)算符),重載操作符必需要用operator修飾以允許使用!
解構(gòu)聲明componentN函數(shù)的定義如下:
    class User(val first: String, val second: String) {
        //componentN是操作符,重載它,必須添加operator修飾符
        operator fun component1(): String {
            return first
        }
        operator fun component2(): String {
            return second
        }
    }

    fun main(args: Array<String>) {
        //解構(gòu)聲明會(huì)創(chuàng)建多個(gè)變量,可獨(dú)立使用
        val (f, s) = User("lioil", "win")
        println("$f, $s") //輸出"lioil", "win"
    }

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

編譯器會(huì)為數(shù)據(jù)類(data class)自動(dòng)聲明/定義componentN()函數(shù),可直接用解構(gòu)聲明!    
    data class User(val name: String, val id: Int)

    fun main(args: Array<String>) {
        val u = User("lioil.win", 1)

        //傳統(tǒng)用法
        println("${u.name}, ${u.id}")//輸出: lioil.win, 1

        //解構(gòu)聲明
        val (n, i) = u
        println("$n, $i")//輸出: lioil.win, 1

        //直接調(diào)用componentN函數(shù)
        println("${u.component1()}, ${u.component2()}")
    }

函數(shù)返回多個(gè)變量(Return Values)

如果需要一個(gè)函數(shù)返回多個(gè)變量,Kotlin最簡(jiǎn)潔的實(shí)現(xiàn)是聲明一個(gè)數(shù)據(jù)類并返回其實(shí)例對(duì)象,
數(shù)據(jù)類(data class)自動(dòng)聲明/定義componentN()函數(shù),無需我們定義!
    data class Result(val result: Int, val status: Status)

    fun deFun(...): Result {
        return Result(result, status)
    }

    //函數(shù)直接返回多個(gè)變量,非常方便使用
    val (result, status) = deFun(...)

for循環(huán)-解構(gòu)聲明

collection的元素類必須要聲明component1()媚创、component2()等函數(shù)
    for ((a, b) in collection) {
        print(a)  
        ...                
    }

映射Map-解構(gòu)聲明

在kotlin標(biāo)準(zhǔn)庫(standard library)提供以下擴(kuò)展:
    //iterator()用于map迭代遍歷(循環(huán))
    operator fun <K, V> Map<K, V>.iterator(): Iterator<Map.Entry<K, V>> = entrySet().iterator()

    //component1渗钉、component2用于解構(gòu)Map.Entr對(duì)象,獲取鍵值對(duì)(key,value)
    operator fun <K, V> Map.Entry<K, V>.component1() = getKey()
    operator fun <K, V> Map.Entry<K, V>.component2() = getValue()

Map解構(gòu)聲明的實(shí)例:
    fun main(args: Array<String>) {
        val map = hashMapOf<String, Int>()
        map.put("one", 1)
        map.put("two", 2)

        //(key, value) in map
        for ((key, value) in map) {
            println("key = $key, value = $value")
        }
    }

函數(shù)默認(rèn)值

在Java中經(jīng)常會(huì)因?yàn)槟硞€(gè)函數(shù)需要傳入的參數(shù)數(shù)量不同而需要寫很多同名的函數(shù),即方法的重載
在Kotlin的函數(shù)規(guī)則中钞钙,可以為每個(gè)參數(shù)設(shè)置一個(gè)默認(rèn)值鳄橘,在沒有傳入該參數(shù)時(shí)啟用默認(rèn)值

注意:可以省略的只有排在末尾的參數(shù)声离。

fun addUser(name: String = "無名", age: Int = 100, sex: Char = '男', id: Int = -1) {}
  addUser()
  addUser("張三")
  addUser("李四", 10)
  addUser("王五", 10, '男', 1)

如果使用命名參數(shù)就可以指定你要設(shè)置的任何參數(shù)。

addUser(age = 5, id = 10)
addUser("趙六",sex = '妖')

命名參數(shù)

命名參數(shù)可以在我們調(diào)用某個(gè)方法時(shí)顯式的寫出我們傳入的參數(shù)名以及對(duì)應(yīng)值瘫怜,這樣能提高我們代碼的可閱讀性术徊。

建議多使用命名參數(shù)來增加代碼的可讀性

fun test(key:Int,value:String)
test(key = 1,value = "one")

既然借助編輯器已經(jīng)能夠?qū)崿F(xiàn)優(yōu)化閱讀的效果,那為什么還要引入命名參數(shù)呢宝磨?雞肋弧关?

當(dāng)使用函數(shù)默認(rèn)值時(shí),本來是只能通過參數(shù)順序進(jìn)行參數(shù)傳入和缺省唤锉,但是有了命名參數(shù)后可以完全忽略參數(shù)位置世囊,直接賦值給你想要的任何參數(shù)。

fun addUser(name: String = "無名", age: Int = 100, sex: Char = '男', id: Int = -1) {}
  addUser(age = 5, id = 10)
  addUser("趙六",sex = '妖')

賦值為空

Java中有一個(gè)判斷是

if((str=bufferedReader.readLine())!= null)

這句話到了kotlin轉(zhuǎn)不過來
最初我是這么寫的

var str=bufferedReader.readLine()
while(str != null){
執(zhí)行代碼
}

可是讀到bufferedReader.readLine()=null時(shí)報(bào)錯(cuò)了
java.lang.IllegalStateException: bufferedReader.readLine() must not be null

問題在哪呢窿祥?問題在str的聲明上
改成

var str: String ?=null
str=bufferedReader.readLine()
while (str != null) {
buffer.append(str)
str = bufferedReader.readLine()
}

就不再報(bào)錯(cuò)了株憾,因?yàn)樵诤笠环N聲明方式中str允許為空了

return

在kotlin線程中return時(shí)會(huì)報(bào)錯(cuò),正確的方式是
return@Runnable

領(lǐng)域特定語言(DSL)

DSL是什么

編程語言晒衩,比如Java嗤瞎、kotlin都屬于編程語言,而DSL全稱為“領(lǐng)域特定語言”听系。以下為兩者的對(duì)比:

- 編程語言:有一系列足夠完善的能力來解決幾乎所有能被計(jì)算機(jī)解決的問題贝奇。
- DSL:專注在特定任務(wù),或者說領(lǐng)域上靠胜,并放棄與該領(lǐng)域無關(guān)的功能掉瞳。

可以看出,專門針對(duì)某一特殊功能所存在的語言并且僅能完成這部分功能的語言我們稱之為領(lǐng)域特定語言浪漠。常見的有DSL有SQL和正則表達(dá)式陕习。

內(nèi)嵌DSL

內(nèi)嵌DSL作為kotlin的一種新特性,可以方便我們的開發(fā)址愿。那為什么要使用內(nèi)嵌DSL而不是直接使用呢该镣,以SQL為例。

這些語言為了更有效的完成它們的目標(biāo)响谓,通過會(huì)減少它們提供的功能损合,因此當(dāng)你需要執(zhí)行一個(gè)SQL語句的時(shí)候,不用聲明一個(gè)類或者方法娘纷,每一個(gè)關(guān)鍵字就代表了需要執(zhí)行的操作和類型塌忽,每種類型的操作都有自己獨(dú)特的語法和針對(duì)特定任務(wù)的關(guān)鍵字集合。

并且往往DSL語言更趨向于聲明式失驶,和通用編程語言相反,大部分是命令枣购。

這導(dǎo)致直接使用DSL有個(gè)缺點(diǎn):它們很難與使用通用編程語言的宿主應(yīng)用程序結(jié)合起來使用嬉探。簡(jiǎn)單來說就是語法不同擦耀,需要以字符串等其他形式傳入,不便于及時(shí)糾錯(cuò)涩堤。

示例

Anko SQLite(SQL)

fun getUsers(db: ManagedSQLiteOpenHelper): List<User> = db.use {
    db.select("Users")
            .whereSimple("family_name = ?", "John")
            .doExec()
            .parseList(UserParser)
}

Anko Layouts(XML)

verticalLayout {
    val name = editText()
    button("Say Hello") {
        onClick { toast("Hello, ${name.text}!") }
    }
}
總結(jié)

kotlin用內(nèi)嵌DSL的方式讓一些特殊領(lǐng)域語言的編寫變得更加容易和統(tǒng)一眷蜓。當(dāng)熟練后甚至可以不用再寫XML文件來布局,不用再寫難記又不方便調(diào)試的SQL語句胎围。

其實(shí)現(xiàn)的原理也很簡(jiǎn)單吁系,實(shí)際上就是普通的方法基于lambda表達(dá)式的形式完成高度簡(jiǎn)潔的代碼風(fēng)格。說白了就是以代碼形式完成以上的功能白魂,不過這些代碼是經(jīng)過kotlin深度封裝和優(yōu)化的汽纤。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市福荸,隨后出現(xiàn)的幾起案子蕴坪,更是在濱河造成了極大的恐慌,老刑警劉巖敬锐,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件背传,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡台夺,警方通過查閱死者的電腦和手機(jī)径玖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來颤介,“玉大人梳星,你說我怎么就攤上這事÷蚩撸” “怎么了丰泊?”我有些...
    開封第一講書人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)始绍。 經(jīng)常有香客問我瞳购,道長(zhǎng),這世上最難降的妖魔是什么亏推? 我笑而不...
    開封第一講書人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任学赛,我火速辦了婚禮,結(jié)果婚禮上吞杭,老公的妹妹穿的比我還像新娘盏浇。我一直安慰自己,他們只是感情好芽狗,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開白布绢掰。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪滴劲。 梳的紋絲不亂的頭發(fā)上攻晒,一...
    開封第一講書人閱讀 51,482評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音班挖,去河邊找鬼鲁捏。 笑死,一個(gè)胖子當(dāng)著我的面吹牛萧芙,可吹牛的內(nèi)容都是我干的给梅。 我是一名探鬼主播,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼双揪,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼动羽!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起盟榴,我...
    開封第一講書人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤曹质,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后擎场,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體羽德,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年迅办,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了宅静。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡站欺,死狀恐怖姨夹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情矾策,我是刑警寧澤磷账,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站贾虽,受9級(jí)特大地震影響逃糟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蓬豁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一绰咽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧地粪,春花似錦取募、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽斗忌。三九已至,卻和暖如春聊品,著一層夾襖步出監(jiān)牢的瞬間飞蹂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工翻屈, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人妻坝。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓伸眶,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親刽宪。 傳聞我的和親對(duì)象是個(gè)殘疾皇子厘贼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

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