Kotlin學(xué)習(xí)4

集合

List、set 、map 分兩類,只讀和可變

List創(chuàng)建與元素獲取

getOrElse是一個(gè)安全索引取值函數(shù),他需要兩個(gè)參數(shù),第一個(gè)是索引值,第二個(gè)是能提供默認(rèn)值的lambda表達(dá)式,如果索引值不存在的話,可用來代替異常。

getOrNull是Kotlin提供的另一個(gè)安全索引取值函數(shù),他返回null結(jié)果,而不是拋出異常。

fun main(){
  val list :List<String> = listOf("jason","jack","jacky")
  //list[4]
  println(list.getOrElse(4){"Unknown"})//Unknown
  println(list.getOrNull(4))//null
  println(list.getOrNull(4)?:"Unknow")
}

可變List集合

在Kotlin中,支持內(nèi)容修改的列表叫可變列表,要?jiǎng)?chuàng)建可變列表,可以使用mutableListOf函數(shù)。list還支持使用toList和toMutableList函數(shù)動(dòng)態(tài)實(shí)現(xiàn)只讀列表和可變列表的相互轉(zhuǎn)換。

fun main(){
  val mutableList = mutableListOf("jason","jack","jacky")
  mutableList.add("jimmy")
  mutableList.remove("jack")
  println(mutableList)
  
  listOf("jason","jack","jacky").toMutableList()
  mutableListOf("jason","jack","jacky").toList()
}

mutator函數(shù)

能夠修改可變列表的函數(shù)有個(gè)統(tǒng)一的名字:mutator函數(shù)
添加元素運(yùn)算符與刪除元素運(yùn)算符
基于lambda表達(dá)式指定的條件刪除元素

fun main(){
  val mutableList =mutableListOf("jason","jack","jacky")
  mutableList += "jimmy"
  println(mutableList)

  mutableList -="jason"
  println(mutableList)
  
//removeIf
  mutableList.removeIf{it.contains("jack")}
  println(mutableList)
}

List集合遍歷

for in 遍歷
forEach 遍歷
forEachIndexed遍歷時(shí)要獲取索引

fun mian(){
  val list = listOf("jason","jack","jacky")
  for(s :String in list){
    println(s)
  }
  list.forEach{
    println(it)
  }
  list.forEachIndexed {index,item->
    println("$index, $item")
  }
}

解構(gòu)語(yǔ)法過濾元素

通過_符號(hào)過濾不要的元素

fun main(){
  val list = listOf("jason","jack","jacky")
  val (origin,_,proxy) = list
}

set集合

set創(chuàng)建與元素獲取

list可以有重復(fù)的;set不可以
通過setOf創(chuàng)建set集合,使用elementAt函數(shù)讀取集合中的元素

fun main(){
  val set = setOf("Kotlin","Java","Scala")
  //set[3]//  沒有這種寫法
  set.elementAt(2)
}

可變set集合

通過mutableSetOf創(chuàng)建可變的set集合

fun main(){
  val mutableSet = mutableSetOf("Kotlin","Java","Scala")
  mutableSet +="Groovy"
}

集合轉(zhuǎn)換與快捷函數(shù)

把list轉(zhuǎn)換成set,去掉重復(fù)元素
快捷函數(shù)

fun main(){
  val list = listOf("jason","jack","jacky","jacky" )
        .toSet()
        .toList()
  println(list)
   
  println(listOf("jason","jack","jacky","jacky").distinct())
}

數(shù)組類型

Kotlin提供各種Array,雖然是引用類型,但是可以編譯成java基本數(shù)據(jù)類型

11.png
fun main(){
  val intArray = intArrayOf(10,20,30)
  listOf(10,20,30).toIntArray()
  
}

map集合

map的創(chuàng)建

to看上去像關(guān)鍵字,實(shí)際上,他是個(gè)省略了點(diǎn)號(hào)和參數(shù)的特殊函數(shù),to函數(shù)將它左邊和右邊的值轉(zhuǎn)化成一對(duì)Pair

fun main(){
  val map = mapOf("Jack" to 20,"Jason" to 18,"Jacky" to 30)
  println(map)
  
  mapOf(Pair("Jack",20),Pair("Jason",18))
}

獲取map的值

[]取值運(yùn)算符,讀取鍵對(duì)應(yīng)的值,如果鍵不存在就返回null
getValue,讀取鍵對(duì)應(yīng)的值,如果鍵不存在就拋出異常
getOrElse,讀取鍵對(duì)應(yīng)的值,或者使用匿名函數(shù)返回默認(rèn)值
getOrDefault,讀取鍵對(duì)應(yīng)的值,或者返回默認(rèn)值

fun main(){
  val map = mapOf("Jack" to 20,"Jason" to 18,"Jacky" to 30)
  println(map["Jack"])//30
  println(map.getValue("Jack"))//30
  println(map.getOrElse("Rose"){"unknow"})//unknow
  println(map.getOrDefault("Rose"),0)//0
}

遍歷map

forEach

fun main(){
  val map = mapOf("Jack" to 20,"Jason" to 18,"Jacky" to 30)
  map.forEach{ it :Map.Entry<String,Int>
    println("${it.key} , ${it.value}")
  }
  map.forEach{ (key:String, value:Int) ->
    println("${key} , ${value}")
  }
}

可變map集合

通過mutableMapOf創(chuàng)建可變map
getOrPut鍵值不存在,就添加并返回結(jié)果,否則就返回已有鍵對(duì)應(yīng)的值

fun main(){
  val mutableMap = mutableMapOf("Jack" to 20,"Jason" to 18,"Jacky" to 30)
  mutableMap +="Jimmy" to 30
  mutableMap.put("Jimmy",31)//覆蓋了

  println(mutableMap.getOrPut("Jimmy"){18})
  mutableMap.getOrPut("Rose"){18}
  println(mutableMap )
}

定義類與field關(guān)鍵字

針對(duì)你定義的每一個(gè)屬性,kotlin都會(huì)產(chǎn)生一個(gè)field,一個(gè)get,一個(gè)setter,field用來存儲(chǔ)屬性數(shù)據(jù),你不能直接定義field,kotlin會(huì)封裝field,保護(hù)她里面的數(shù)據(jù),質(zhì)保路給getter和setter使用。屬性的getter方法決定你如何讀取屬性值,每個(gè)屬性都有g(shù)etter方法,setter方法決定你如何給屬性賦值,所以只有可變屬性才會(huì)有setter方法,盡管kotllin會(huì)自動(dòng)提供默認(rèn)的getter和setter方法,但在需要控制如何讀寫屬性數(shù)據(jù)時(shí),你也可以自定義他們。

class player{
  var name = "jack"
        get() = field.capitalize()
        set(value){
          field = value.trim()
        }
}

計(jì)算屬性與防范競(jìng)態(tài)條件

計(jì)算屬性是通過一個(gè)覆蓋的get或set運(yùn)算符來定義的,這時(shí)field就不需要了

class Player{
  val rolledValue
        get()=(1..6).shuffled().first()
 }

如果一個(gè)類的屬性即可空又可變,那么引用他之前你必須保證他非空,一個(gè)辦法是用also標(biāo)準(zhǔn)函數(shù)

class Player{
  var words:String ?="hello"

  fun say(){
    words?.also{it:String
      println("hello ${it.toUpperCase()}")
    }
  }
}

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

我們?cè)赑layer類的定義頭中定義一個(gè)柱構(gòu)造函數(shù),使用臨時(shí)變量為player的各個(gè)屬性提供初始值,在kotlin中,為便于識(shí)別,臨時(shí)變量(包括僅僅引用一次的參數(shù)),通常都會(huì)以下劃線開頭的名字命名。

class Player(
  _name:String,
  _age:Int,
  _isNormal:Boolean
){
  var name = _name
        get() = field.capotalize()
        set(value){
          field = value.trim()
        }
  var age = _age
  var isNormal = _isNormal
}
fun main(){
  var player = Player("jack",20,true)
}

在柱構(gòu)造函數(shù)里定義屬性

kotlin允許你不使用臨時(shí)變量賦值,而是直接用一個(gè)定義同時(shí)指定參數(shù)和類屬性,通常,我們更喜歡用這種方式定義類屬性,因?yàn)槟軠p少重復(fù)代碼

class Player2(
  _name:String,
  var age:Int,
  val isNormal:Boolean
){
  var name = _name
        get() = field.capotalize()
        set(value){
          field = value.trim()
        }
}

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

可以定義多個(gè)次構(gòu)造函數(shù)來配置不同參數(shù)組合

class Player2(
  _name:String,
  var age:Int,
  val isNormal:Boolean
){
  var name = _name
        get() = field.capotalize()
        set(value){
          field = value.trim()
        }

  constructor(_name:String):this(_name,
                                          age=100
                                          isNormal = false){
    //...
  }
}

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

定義構(gòu)造函數(shù)時(shí)可以指定默認(rèn)值。

class Player3(
  _name:String,
  var age:Int = 20,
  val isNormal:Boolean
){
  var name = _name
        get() = field.capotalize()
        set(value){
          field = value.trim()
        }
}

初始化塊

初始化塊可以設(shè)置變量或值,以及執(zhí)行有效性檢查,如檢查傳給某構(gòu)造函數(shù)的值是否有效,初始化塊代碼會(huì)在構(gòu)造類實(shí)例時(shí)執(zhí)行。

init{
  require(age>0){"age must be positive"}
  require(name.isNotBlank()){"must have a name"}
}

初始化順序

主構(gòu)造函數(shù)里聲明的屬性
類級(jí)別的屬性賦值
init初始化塊里的屬性賦值和函數(shù)調(diào)用
次構(gòu)造函數(shù)里的屬性賦值和函數(shù)調(diào)用

class Student(
  _name:String,
  val age:Int
){
  var name = _name
  var score = 10
  private val hobby ="music"
  val subject :String

  init {
    println("initializing student")
    subject = "math"
  }

  constructor(_name :String):this(_name,10){
    score = 20
  }
}
fun main(){
  Student("Jack")
}
12.png

延遲初始化lateinit

使用lateinit關(guān)鍵字相當(dāng)于做了一個(gè)約定:在用它之前負(fù)責(zé)初始化
只要無法確認(rèn)lateinit變量是否完成初始化,可以執(zhí)行inInitialized檢查

class Player4{
  laterinit var equipment:String
  fun ready(){
    equipment = "sharp knife"
  }
  fun battle(){
    if(::equipment.isInitialized)println(equipment)//沒有初始化就不執(zhí)行了
  }
}
fun main(){
  val p = Player4()
  p.ready()//如果忘了就異常了
  p.battle()
}

惰性初始化by lazy

暫時(shí)不初始化某個(gè)變量,直到首次使用它

class Player5(_name :String){
  var name = _name
  val config by lazy{loadConfig()}
  private fun loadConfig():String{
    println("loading...")
    return "xxx"
  } 
}
fun main(){
  val p = Player5("Jack")
  Thread.sleep(3000)
  println(p.config)
}

初始化陷阱1

在初始化塊時(shí),順序非常重要,必須保證塊中所有屬性已完成初始化。

class Player6(){
  init{
    val bloodBonus = blood.times(4)//blood 報(bào)錯(cuò)
  }
  val blood = 100
}

雖然 類級(jí)別屬性 比初始化塊的 先初始化,但還是要放在前面。順序不能反了,從上到下。

class Player6(){
  val blood = 100//要在前面
  init{
    val bloodBonus = blood.times(4)
  }
}

初始化陷阱2

下面這個(gè)便已沒有問題,因?yàn)榫幾g器看到name已經(jīng)在init里初始化了,但是代碼一運(yùn)行,就會(huì)拋出空指針異常,因?yàn)閚ame屬性還沒賦值,firstLetter函數(shù)就用了他。

class Player7(){
  val name :String
  private fun firstLetter() = name[0]
  
  init {
    println(firstLetter())
    name = "Jack"http://和上面一行換一下就可以了
  }
}

初始化陷阱3

因?yàn)榫幾g器看到所有屬性都初始化了,所以編譯沒有問題,但運(yùn)行確是null。
因?yàn)樵谟胕nitPlayerName函數(shù)初始化playerName時(shí),name屬性還沒有完成初始化

class Player8(_name :String){
  val playerName:String = initPlayerName()//這時(shí)拿到的是null
  val name:String = _name//把這行放到第一行即可
  private fun initPlayerName() = name
}
fun main(){
  println(Player8("Jack").playerName)
}

小結(jié)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容