kotlin筆記

kotlin優(yōu)勢
簡潔(data class自帶get set equals hashCode toString copy
安全(區(qū)別可空和不可空婉刀,避免各類空指針)
與java互操作性

基礎(chǔ)特性及用法

顯式

Kotlin 通過細(xì)致的顯式聲明和約束,使代碼的邏輯和結(jié)構(gòu)都更加清晰棒动,并減少錯(cuò)誤。

  • 可變與只讀
    var 聲明可變變量
    val 聲明制度變量
    只讀集合 List<T> Set<T> Map<K, V>
    可變集合 MutableList<T> MutableSet<T> MutableMap<K, V>

  • 類型安全
    是靜態(tài)隱式類型的,提供類型推斷

  • 空引用安全
    區(qū)分可空與非空
    可空安全調(diào)用bob?.department?.head?.name
    Elvis操作符:如果 ?: 左邊的表達(dá)式不為 null,則返回該表達(dá)式;否則返回 null

      val l = b?.length ?: ‐1
      // 等效于
      val l: Int = if (b != null) b.length else ‐1
    

集合
集合也可以根據(jù)是否允許容納 null進(jìn)行區(qū)分(List<Int?> / List<Int> )。
可以使用 filterNotNull()從可為空類型的集合中過濾非空類型。

  • 修飾符
    可見性
    peivate: 類內(nèi)可見
    protectedprivate+子類可見
    internal:同一模塊(一起編譯的一組kotlin源文件)
    public:可見

open:用于繼承的類要顯示的聲明open

inner:內(nèi)部類碴开,默認(rèn)內(nèi)部類不能訪問外部類
使用inner標(biāo)記的類會攜帶外部類引用巴碗,可以訪問外部類成員

  • 工程化

數(shù)據(jù)類解構(gòu)聲明
data class User(val name: String = "", val age: Int = 0)
數(shù)據(jù)類自動(dòng)對每個(gè)屬性生成對應(yīng)的componentN()函數(shù)明垢,用于解構(gòu)聲明: val jane = User("Jane", 35)
val (name, age) = jane

  • 擴(kuò)展函數(shù)
    kotlin提供了對類擴(kuò)展的功能溯革,可以在不繼承或使用設(shè)計(jì)模式(如裝飾著)的情況下抖单,為類添加新的功能

    下面為 MutableList<Int> 添加了一個(gè) swap() 函數(shù):
    fun MutableList<Int>.swap(index1: Int, index2: Int) {
     val tmp =    this[index1] // this 對應(yīng)列表本身 this[index1] = this[index2]
     this[index2] = tmp
    }

同時(shí)聲明以下兩個(gè)函數(shù)回導(dǎo)致沖突:

fun String?.toDecimal(): BigDecimal {...}
fun toDecimal(value: String?): BigDecimal {...}  

擴(kuò)展函數(shù)是靜態(tài)解析的货矮,其調(diào)用取決于聲明類型而不是運(yùn)行時(shí)的實(shí)際類型

open class C class D: C()
fun C.foo() = "c" fun D.foo() = "d"
fun printFoo(c: C) {
println(c.foo())
}
printFoo(D()) // c
  • 操作符重載

// todo

進(jìn)階特性及用法

kotlin中函數(shù)的地位

kotlin中函數(shù)是頭等的燃少≌颍可以存儲在變量與數(shù)據(jù)結(jié)構(gòu)中矮烹、可以作為參數(shù)傳遞給高階函數(shù)仁期、也可以從高階函數(shù)返回。

高階函數(shù)

高階函數(shù)是將函數(shù)用作參數(shù)或返回值的函數(shù)理逊。

fun <T> lock(lock: Lock, body: () ‐> T): T {
    lock.lock()
    try {
     return body()
    }
    finally {
     lock.unlock()
   }
}

上述代碼中道媚,body就是函數(shù)類型,該函數(shù)沒有輸入?yún)?shù),輸出類型為T舀奶。 它被 lock 保護(hù)腹躁,在 try 塊中調(diào)用,其結(jié)果由 lock() 函數(shù)返回。 lock() 的調(diào)用方法如下套硼。

fun toBeSynchronized() = sharedResource.operation()
val result1 = lock(myLock, ::toBeSynchronized)
val result2 = lock(myLock, { sharedResource.operation() })

函數(shù)類型

Kotlin 使用類似 (Int) -> String 的一系列函數(shù)類型來處理函數(shù)的聲明: val onClick: () -> Unit = ……策菜。

這些類型具有與函數(shù)簽名對應(yīng)的特殊標(biāo)示法,即他們的參數(shù)和返回值:

  • 參數(shù)放在()中棵癣,參數(shù)放在 ->左側(cè),返回值放在 ->右側(cè)。參數(shù)列表可為空敞临,返回類型不可省略攀涵,如:()->Unit

  • 參數(shù)類型可以有一個(gè)額外的接收者類型踪区,他的表示法如:A.(B) -> C。它表示溪椎,參數(shù)A對象中有一個(gè)方法接收一個(gè)B類型的參數(shù),并返回C。

  • 掛起函數(shù) 一種特殊類型的函數(shù)椿浓,有一個(gè)suspend修飾符荠瘪。如suspend ()->Unit

  • 函數(shù)類型指定為可空需使用圓括號 ((Int,Int) -> Int)?

  • 函數(shù)類型可以使用圓括號結(jié)合(Int -> (Int -> Int))

  • 箭頭表示法是右結(jié)合的 (Int -> (Int -> Unit)) 等價(jià)于(Int -> Int -> Unit)但不等價(jià)于((Int -> Int) -> Unit)

還可以通過類型別名給函數(shù)類型起一個(gè)別稱:

 typealias ClickHandler = (Button,ClickEvent) ->Unit

函數(shù)類型實(shí)例調(diào)用

函數(shù)類型的值可以通過invoke(...)調(diào)用:f.invoke(x)或者直接f(x)

如果該值具有接收者類型臀突,那么應(yīng)該將接收者作為第一個(gè)參數(shù)傳遞。調(diào)用接收者的函數(shù)值類型的另一個(gè)方式是在其前面加上接收者對象啊胶,就好比該值是一個(gè)擴(kuò)展函數(shù):

val stringPlus: (String, String) -> String = String::plus
val intPlus: Int.(Int) -> Int = Int::plus

println(stringPlus.invoke("<-", "->"))
println(stringPlus("Hello, ", "world!")) 

println(intPlus.invoke(1, 1))
println(intPlus(1, 2))
println(2.intPlus(3)) // 類擴(kuò)展調(diào)用
  • Lamda表達(dá)式
    沒有經(jīng)過聲明而直接作為表達(dá)式傳遞的函數(shù)诫尽。
    編寫規(guī)則:
    1.Lamda表達(dá)式要被{}包圍
    2.參數(shù)(參數(shù)類型可以省略)在->左邊
    3.函數(shù)體在-> 右邊
    4.最后一個(gè)表達(dá)式作為函數(shù)的返回值
    val sum1: (Int, Int) ‐> Int = { x, y ‐> x + y }
    val sum2 = { x: Int, y: Int ‐> x + y }
    sum1(1, 2)
    sum2(1, 2)

如果函數(shù)的最后一個(gè)參數(shù)為表達(dá)式,且你傳遞的是Lamda表達(dá)式炬守,那么kotlin的慣例是把Lamda表達(dá)式寫在括號外面:

lock(myLock, { sharedResource.operation() })
// 等效于
lock (myLock) {
 sharedResource.operation()
}
  • 閉包

Lambda表達(dá)式和匿名函數(shù)可以訪問其閉包牧嫉,也就是外部作用域聲明的變量。不同的是减途,java可以修改從閉包中獲取的變量驹止。

  • 匿名函數(shù)

      val isOdd: (Int) -> Boolean = fun(value: Int): Boolean {
          return value % 2 == 1 
      }
    
      val isOdd = fun(value: Int): Boolean {
          return value % 2 == 1 
      }
    
      val isOdd = fun(value: Int): Boolean = value % 2 == 1
    

使用

    val values = listOf(1, 2, 3, 4, 5)
    val filtered = filter(values, isOdd)
  • 可調(diào)用引用
    1.引用頂層、局部观蜗、成員臊恋、擴(kuò)展函數(shù):::isOdd String::toInt
    2.引用頂層、成員墓捻、擴(kuò)展屬性: List<Int>::size
    3.引用構(gòu)造器: ::Regex

      val filtered = filter(values, ::isOdd)
    
  • 實(shí)現(xiàn)了函數(shù)類型接口的類抖仅。使用方法同普通類一樣,定義方法如下:

      class OddChecker: (Int) -> Boolean {
          override fun invoke(value: Int): Boolean {
             return value % 2 == 1 
          }  
       }
    
  • Lambda語法糖

如果Lambda只有一個(gè)參數(shù)砖第,且編譯器可以推斷其類型撤卢,則可以省略參數(shù),此時(shí)該參數(shù)會被隱式的聲明為it

val isOdd: (Int) -> Boolean = { value -> value % 2 == 1 } val isOdd: (Int) -> Boolean = { it % 2 == 1 }
val isOdd: (Int) -> Boolean = { it % 2 == 1 }

如果省略回影響編譯器的類型推斷梧兼,則不可省略

val isOdd = { value: Int -> value % 2 == 1 }

如果函數(shù)只返回一個(gè)表達(dá)式放吩,則可以省略函數(shù)體的大括號(和返回類型),使用 = 連接函數(shù)體

fun double(x: Int): Int { return x * 2 } 
fun double(x: Int): Int = x * 2
fun double(x: Int) = x * 2
  • 純函數(shù)
    1.對于同樣的輸入羽杰,返回同樣的輸出
    2.調(diào)用函數(shù)不會產(chǎn)生副作用(不會修改程序狀態(tài))
  • 內(nèi)置函數(shù)

    let T的擴(kuò)展函數(shù)渡紫,將block中的操作應(yīng)用在T上,并返回block的值考赛,在block中使用it引用T的實(shí)例
    also T的擴(kuò)展函數(shù)惕澎,將block中的操作應(yīng)用在T上,并返回T颜骤,在block中使用it引用T的實(shí)例
    withblock中的操作應(yīng)用在T上唧喉,并返回block的值,不是擴(kuò)展函數(shù),block中使用this引用T的實(shí)例
    run T的擴(kuò)展函數(shù)八孝,將block中的操作應(yīng)用在T上董朝,并返回block的值,在block中使用this引用T的實(shí)例
    apply T的擴(kuò)展函數(shù)干跛,將block中的操作應(yīng)用在T上益涧,并返回T,在block中使用this引用T的實(shí)例

  • 集合的操作

      var records: List<FoodRecord> = ...
      val models: List<FoodModel> =
      records // List<FoodRecord>
      .map { it.transform() } // List<FoodModel> .filter { it.units.isNotEmpty() } // List<FoodModel> .map { food ->
      food.units.map { unit -> food.deepCopy(listOf(unit)) } } //List<List<FoodModel>> .flatten() // List<FoodModel>
      
      val foodMap: Map<String, List<FoodModel>> = models.groupBy { it.foodCategoryName }
    
  • 參數(shù)默認(rèn)值和命名參數(shù)

      fun reformat(str: String,normalizeCase: Boolean = true,upperCaseFirstLetter: Boolean = true, divideByCamelHumps: Boolean = false, wordSeparator: Char = ' ') {
       ... 
      }
    

默認(rèn)參數(shù)調(diào)用

reformat(str)

指定參數(shù)調(diào)用

reformat(str, true, true, false, '_')

使用命名參數(shù)驯鳖,提高代碼可讀性

reformat(str,normalizeCase = true,upperCaseFirstLetter = true,divideByCamelHumps = false,wordSeparator = '_')
  • 委托屬性

使用如下形式聲明委托屬性

class Example {
  var p: String by Delegate() 
}

實(shí)現(xiàn)委托

 class Delegate {
     operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return "$thisRef, thank you for delegating '${property.name}' to me!" }
    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        println("$value has been assigned to '${property.name}' in $thisRef.")
     }
  }

使用

val e = Example()
e.p = "HelloWorld" // HelloWorld has been assigned to 'p' in    Example@17f052a3. println(e.p) // Example@17f052a3, thank you for delegating 'p' to me!
  • 標(biāo)準(zhǔn)委托 lazy

      val lazyValue: String by lazy { println("computed!")
           "Hello"
       }
        
      fun main(args: Array<String>) { println("Running in main")    println(lazyValue) println(lazyValue)
      }
    

輸出

 Running in main
 computed!
 Hello
 Hello
  • observable
    Delegates.observable接收兩個(gè)參數(shù):初始值和屬性變化時(shí)的Handler

      class User {
        var name: String by Delegates.observable("<no name>") {
        prop, old, new ->
        println("$old -> $new")
        }
      }
    
      fun main(args: Array<String>) { 
          val user = User()
          user.name = "first"
          user.name = "second"
      }
    

輸出

  <no name> -> first
  first -> second
  • map

      class User(val map: MutableMap<String, Any?>) { 
            var name: String by map
            var age: Int by map 
      }
    
      val user = User(mapOf( "name" to "John Doe","age" to 25 ))
      println(user.name) // John Doe println(user.age) // 25
      user.name = "Mary Sue"
      user.age = 26
      println(user.map) // {name=Mary Sue, age=26}
    
  • 內(nèi)聯(lián)函數(shù)和具體化類型參數(shù)
    使用高階函數(shù)會創(chuàng)建額外的函數(shù)對象并捕獲閉包,帶來額外開銷久免。通過inline標(biāo)注為內(nèi)聯(lián)函數(shù)浅辙,可以避免這些開銷。
    inline會同時(shí)對函數(shù)本身和作為函數(shù)參數(shù)的lambda表達(dá)式生效

    inline fun <T> lock(lock: Lock, body: () -> T): T { lock.lock()
        try {
           return body()
        } finally {
           lock.unlock()
        }
    }

    foo()
    lock(l) { foo() }
    bar()

相當(dāng)于

    foo()
    l.lock() 
    try {
       foo()
    } finally {
       l.unlock() 
    }
    bar()

在內(nèi)聯(lián)函數(shù)中使用 reified 將范型標(biāo)記為具體化類型參數(shù)阎姥,在內(nèi)聯(lián)函數(shù)中记舆,可以像訪問參數(shù)一樣訪問具體化類型參數(shù)。

  inline fun <reified T: Any> fromJson(json: String): T =
  gson.fromJson(json, T::class.java) 
  val user = fromJson<User>(json)
  val user: User = fromJson(json)
  • 支持字段
    在類或累的主構(gòu)造器中使用varval聲明類的屬性呼巴,不能再類中聲明Filed泽腮,Kotlin會自動(dòng)在需要的時(shí)候?yàn)閷傩蕴砑右粋€(gè)支持字段。
    class Person {
          var age: Int = 10
              get() {
                  return field 
              }
              set(value) {
                  field = value
              }
    }
  • 具有支持字段的屬性

    如果屬性使用了至少一個(gè)默認(rèn)的訪問器(get/set)衣赶,或者自定義訪問器中使用了filed標(biāo)識符訪問了支持字段诊赊,則會生成對應(yīng)的支持字段。

    class Person(
      val name: String,
      var age: Int){
      val isAdult: Boolean = age >= 18
    

    }
    這里的isAdult相當(dāng)于java的

    public final boolean isAdult = age >= 18
    val person = Person("John", 17)
    println(person.isAdult) \ false p
    erson.age++
    println(person.isAdult) \ false

  • 沒有支持字段的屬性

      class Person(
         val name: String,
         var age: Int
      ){
           val isAdult: Boolean
                get() {
                 return age >= 18 
                }
      //   等同于get() = age >= 18
      }
    

這里的isAdult相當(dāng)于java的

  public boolean isAdult() {
        return age >= 18; 
  }

  val person = Person("John", 17) 
  println(person.isAdult) \\ false 
  person.age++ 
  println(person.isAdult) \\ true
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末府瞄,一起剝皮案震驚了整個(gè)濱河市碧磅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌遵馆,老刑警劉巖鲸郊,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異货邓,居然都是意外死亡秆撮,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進(jìn)店門换况,熙熙樓的掌柜王于貴愁眉苦臉地迎上來职辨,“玉大人,你說我怎么就攤上這事戈二〔Υ遥” “怎么了?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵挽拂,是天一觀的道長惭每。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么台腥? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任宏赘,我火速辦了婚禮,結(jié)果婚禮上黎侈,老公的妹妹穿的比我還像新娘察署。我一直安慰自己,他們只是感情好峻汉,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布贴汪。 她就那樣靜靜地躺著,像睡著了一般休吠。 火紅的嫁衣襯著肌膚如雪扳埂。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天瘤礁,我揣著相機(jī)與錄音阳懂,去河邊找鬼。 笑死柜思,一個(gè)胖子當(dāng)著我的面吹牛岩调,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播赡盘,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼号枕,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了陨享?” 一聲冷哼從身側(cè)響起堕澄,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎霉咨,沒想到半個(gè)月后蛙紫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡途戒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年坑傅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片喷斋。...
    茶點(diǎn)故事閱讀 39,711評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡唁毒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出星爪,到底是詐尸還是另有隱情浆西,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布顽腾,位于F島的核電站近零,受9級特大地震影響诺核,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜久信,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一窖杀、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧裙士,春花似錦入客、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽霎冯。三九已至着绊,卻和暖如春琼懊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背肮帐。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留边器,地道東北人训枢。 一個(gè)月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像忘巧,于是被迫代替她去往敵國和親恒界。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評論 2 353

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

  • 關(guān)鍵字 var val var name = "張三" name = "李四" //true name = 1/...
    SlideException閱讀 431評論 0 0
  • a === b 當(dāng)且僅當(dāng) a 和 b 指向同一個(gè)對象時(shí)求值為 true砚嘴。 如果為語句加上雙感嘆號:!! 那么則表示...
    麥兜叮叮當(dāng)閱讀 424評論 0 1
  • Kotlin筆記 要理解Java與Kotlin的區(qū)別十酣,就要從最根本的上來理解。Java是解釋型語言(邊解釋成二進(jìn)制...
    FFFSnow閱讀 992評論 0 0
  • 創(chuàng)建對象 類型聲明 字符串模板 方法 Kotlin 特性 : 函數(shù)參數(shù)默認(rèn)值和可變參數(shù) 對Kotlin函數(shù)中的某個(gè)...
    Boyko閱讀 1,133評論 0 2
  • 簡介 Kotlin[https://github.com/JetBrains/kotlin] 是 JetBrain...
    Whyn閱讀 667評論 0 1