基本介紹
- Scala同時支持不可變集合(immutable)和可變集合(mutable)啡专, 不可變集合可以安全滴并發(fā)訪問适肠。ps:一般情況下建議使用不可變集合霍衫。
- scala默認(rèn)采用不可變集合
- scala集合的三大類: 序列Seq,集Set侯养, 映射Map敦跌,所有的集合都擴(kuò)展自Iterable特質(zhì)。
- 不可變集合:scala不可變集合沸毁,就是這個集合本身不能動態(tài)變化(類似于java的數(shù)組峰髓,是不可以動態(tài)增長的)。
- 可變集合:就是這個集合可以動態(tài)變化的(類似于ArrayList息尺,是可以動態(tài)增長的)携兵。
-
繼承關(guān)系圖:
scala的不可變集合繼承關(guān)系圖
scala的可變集合繼承關(guān)系圖
數(shù)組-定長數(shù)組
package com.scala.test
object Test {
def main(args: Array[String]): Unit = {
// 1、數(shù)組-定長數(shù)組:使用new的方式
val arr1 = new Array[Int](10) // 等價于 int[] intArr = new int[10]
arr1(2) = 1000 // 數(shù)組的訪問及元素內(nèi)容的修改用小括號
// 2搂誉、數(shù)組-定長數(shù)組:使用apply函數(shù), 定義的同時賦值
val arr2 = Array(1, 2, "hello") // 泛型是類型推到
// 3徐紧、遍歷數(shù)組1:直接訪問每個元素, 類似于java的增強(qiáng)的for循環(huán):for(int arr : arr2)
for (arr <- arr2) {
println(arr)
}
// 4、遍歷數(shù)組2:使用下標(biāo)訪問, 類似于java的for循環(huán):for(int i = 0; i < arr2.length; i++)
for (idx <- arr2.indices) {
println(arr2(idx))
}
// 5炭懊、scala特有的遍歷方式:將數(shù)組中的每一個元素作用于一個函數(shù)
arr2.foreach(println)
}
}
- 代碼說明:略
數(shù)組-變長數(shù)組
package com.scala.test
import scala.collection.mutable.ArrayBuffer
object Test {
def main(args: Array[String]): Unit = {
// 1并级、變長數(shù)組:變長的數(shù)組, 有點(diǎn)兒類似于java的ArrayList
val arr1 = ArrayBuffer[Int]()
arr1.append(1) // 注意:每次append一次,就在底層重新分配空間侮腹,進(jìn)行擴(kuò)容嘲碧, 然后內(nèi)存地址也會發(fā)生變化,生成新的ArrayBuffer
arr1.append(3, 5) // 追加元素, append函數(shù)參數(shù)是可變參數(shù), 可以直接追加多個元素父阻,類似于java的ArrayList的add方法
arr1 += (7, 9) // 這也可以追加元素
arr1 ++= ArrayBuffer(2, 4, 6) // 把另一個數(shù)組中的元素全部追加到當(dāng)前數(shù)組, 同樣可以看出ArrayBuffer有apply函數(shù)
println(arr1(0)) // 查詢元素:使用小括號
arr1(1) = 5 // 修改指定下標(biāo)的元素值
arr1.remove(1) // 刪除指定下標(biāo)的元素
for (arr <- arr1) { // 循環(huán)遍歷
println(arr)
}
// 2愈涩、以上是ArrayBuffer的基本使用:增刪改查, 但實(shí)際上ArrayBuffer有太多太多的函數(shù)了, 以下列舉出一些常用的函數(shù):
// TODO
}
}
定長數(shù)組與變長數(shù)組的轉(zhuǎn)換
package com.scala.test
import scala.collection.mutable.ArrayBuffer
object Test {
def main(args: Array[String]): Unit = {
val arr1 = Array(1, 3, 5)
val arr2 = ArrayBuffer(2, 4, 6)
val arr1_buffer = arr1.toBuffer
val arr2_array = arr2.toArray
println(arr1_buffer.isInstanceOf[ArrayBuffer[Int]])
println(arr2_array.isInstanceOf[Array[Int]])
}
}
- 底層是先new出一個目標(biāo)對象來,然后將數(shù)據(jù)拷貝的目標(biāo)對象中加矛,由于使用了數(shù)據(jù)拷貝履婉,可能效率較低。
多維數(shù)組
package com.scala.test
import scala.collection.mutable.ArrayBuffer
object Test {
def main(args: Array[String]): Unit = {
val arr = Array.ofDim[Int](3, 4) // 定義一個二維數(shù)組, dim代表是Dimention(即維度), 參數(shù)3和4表示是3行4列
arr(1)(1) = 10 // 給第1行第1列賦值
for (row <- arr) {
for (col <- row) {
print(col + "\t")
}
println()
}
}
}
元組
- 元組可以理解為一個容器斟览,可以存放各種相同或者不同的數(shù)據(jù)毁腿。簡單來說,就是將多個無關(guān)的數(shù)據(jù)封裝為一個整體,稱為元組已烤。
- 注:元組中最大只能有22個元素鸠窗。
package com.scala.test
object Test {
def main(args: Array[String]): Unit = {
// 定義一個元組:定義好后就是一個數(shù)組,只能查詢胯究,不能增刪改
val t1 = (1, 2, "hello", "world")
println(t1)
println(t1._1)
// 元組的遍歷需要用到迭代器
for (item <- t1.productIterator) {
println(item)
}
}
}
不可變列表List
- Scala中的List和java的List不一樣塌鸯,在java中List是一個接口,真正存放數(shù)據(jù)的是ArrayList唐片,而Scala的List可以直接存放數(shù)據(jù),就是一個object涨颜,默認(rèn)情況下费韭,Scala的List的是不可變得,List屬于序列Seq庭瑰。
package com.scala.test
object Test {
def main(args: Array[String]): Unit = {
// 在Scala中, List就是不可變的, 所以導(dǎo)入的是scala.collection.immutalbe.List
// 如果想要使用可變的List, 請使用ListBuffer
// List是存在于scala的包對象中的, 而scala就已經(jīng)默認(rèn)引入了scala包(類似于java的lang包), 所以List不需要import
val list1 = List(1, 2, 3, "hello", "world")
println(list1)
println(list1(1)) // List是Seq下的, 所以是可以用下標(biāo)的
val list2 = Nil // Nil也是定義在scala的包對象中的, 所以也不需要引入, Nil等價于List()
println(list2)
// List列表元素的追加: 這里的追加不是真正的在原先的list上追加星持,而是會返回一個新的列表對象
val list3 = Nil :+ 1 :+ "hello"
val list4 = "hello" +: 1 +: Nil
// 從上面兩個語句看出:
// 0、":+"是往列表的最后添加, 而"+:"永遠(yuǎn)是往列表的首位添加
// 1弹灭、和冒號(即":")挨著的一定是List, 和加號(即"+")挨著的是元素
// 2督暂、支持鏈?zhǔn)阶芳釉? // 3、每一次追加都生成新的列表, 所以可能效率上有點(diǎn)兒慢
println(list3)
println(list4)
// list列表追加另一個list, 將另一個list當(dāng)做一個元素追加到當(dāng)前l(fā)ist中
// 是從有往左運(yùn)行的, 即使將元素或者list追加到另一個List中, 所以::的右邊一定是個List
// val list_err = List("1", "2", 3) :: 9 // 這句話會報錯, 因?yàn)闊o法把一個list追加到一個Int類型中
val list_ok = 9 :: List("1", "2", 3) // 這句話是OK的穷吮,因?yàn)榭梢园岩粋€Int類型元素追加到List中
val list5 = 4 :: 5 :: List("tom", "jerry") :: list3 :: list4 :: Nil
println(list_ok)
println(list5)
// list列表追加另一個list的全部元素:支持一個鏈?zhǔn)秸{(diào)用逻翁,且":::" 可以和 "::" 一起使用
// ::: 這個符號的兩邊一定要都是List才行
// val list_err = 9 ::: List("1", "2", 3) // 這句話會報錯, 因?yàn)樾枰獙⒆筮叺膌ist進(jìn)行flat放入到右邊list中,而Int無法flat
val list_ok2 = Nil ::: List("1", "2", 3) // 這句話OK, 因?yàn)閮蛇叾际荓ist,即使是個空List
println(list_ok2)
val list6 = List("tom", "jerry") ::: list3 ::: list4 :: List("scala", "spark") ::: Nil
println(list6)
}
}
- 從上面代碼可以看到一個現(xiàn)象:追加元素的符號有"+:"捡鱼、":+"八回、"::、":::"驾诈; 但是沒有諸如"+="或"++="
可變列表ListBuffer
package com.scala.test
import scala.collection.mutable.ListBuffer
object Test {
def main(args: Array[String]): Unit = {
// 直接用applay函數(shù)初始化一個ListBuffer, 需要導(dǎo)入包
val lb1 = ListBuffer(1, 2, "hello", "world")
// 遍歷
for (item <- lb1) {
println(item)
}
// 追加元素: 可以追加1個或多個
lb1.append("tom")
lb1.append("scala", "spark")
lb1 += 4
lb1 += (4, 5, 6)
lb1 += ListBuffer("a", "b") // 將整體作為一個元素添加到lb1中
println(lb1)
// 以上都是對lb1直接操作增加內(nèi)容缠诅,而以下操作完會直接生成新的的ListBuffer, 且不改變lb1
val lb2 = lb1 :+ 5
val lb3 = 5 +: lb1
println(lb1)
println(lb2)
println(lb3)
// 對lb1追加兩一個ListBuffer里的全部元素
lb1 ++= lb2
println(lb1)
// ++ 符號, 生成新的ListBuffer
val lb4 = lb1 ++ lb2
println(lb1) // lb1本身不變
println(lb4) // 返回了新的ListBuffer
println("----------移除元素------------")
lb1.remove(2) // 移除下標(biāo)為2的元素
println(lb1)
}
}
- 看上述代碼,總結(jié)出一個問題乍迄,如果是修改ListBuffer本身管引,那么就是帶等于號的(例如:+= 和 ++=),其他的(例如:++ 和 :+ 和 +:)都是會生成新的ListBuffer闯两。
隊(duì)列Queue
- 隊(duì)列是個有序列表褥伴,在底層可以用數(shù)組或者鏈表來實(shí)現(xiàn)。
- 其輸入和輸出要遵循先入先出的原則生蚁。
- 在scala中噩翠,設(shè)計(jì)者已經(jīng)給我們提供了隊(duì)列類使用。
- 有scala.collection.mutable.Queue 和 scala.collection.immtable.Queue邦投, 但是一般來說伤锚,我們在開發(fā)中通常使用可變集合中的隊(duì)列。
package com.scala.test
import scala.collection.mutable
object Test {
def main(args: Array[String]): Unit = {
val queue1 = mutable.Queue(1, 2, 3)
println(queue1)
queue1 += 4
queue1 ++= List(5, 6, 7)
queue1.dequeue() // 從最開始取出一個元素
queue1.enqueue(8, 9, 10) // 往隊(duì)列尾部追加元素
for (item <- queue1) {
println(item)
}
}
}
映射Map
- scala的Map,和java類型屯援,也是一個散列表猛们,存儲的也是鍵值(key-value)對。
- scala中的不可變Map是有序的狞洋,可變Map是無序的弯淘。 一般情況下我們都使用可變的Map。
(1)吉懊、不可變Map
package com.scala.test
object Test {
def main(args: Array[String]): Unit = {
val map = Map("a" -> 1, "b" -> 2, "c" -> 3)
println(map) // 順序不會變
}
}
- 不可變Map是不需要引入包的庐橙,可以直接使用
- 其實(shí)就是一個集合,且是有序集合借嗽, 且集合中的每個元素是Tuple2類型的态鳖。
(2)、 可變Map
package com.scala.test
import scala.collection.mutable
object Test {
def main(args: Array[String]): Unit = {
// 創(chuàng)建map的4個方式:前兩個是聲明一個空的map, 后兩個是聲明有初始值的map
val map0 = new mutable.HashMap[String, String]()
val map1 = mutable.Map[String, Int]()
val map2 = mutable.Map("a" -> 1, "b" -> 2)
val map3 = mutable.Map(("a", 1), ("b", 2))
map0("c") = "C" // key存在則是更新恶导,否則就是增加
map0 += ("a" -> "96")
map1 += ("A" -> 96)
map2 ++= map1
println(map0)
println(map1)
println(map2)
// 查詢某個key的值
println(map0("a"))
// println(map0("aa")) // 如果找不到對應(yīng)的key, 則會報異常
println(if (map0.contains("a")) map0("a") else "key不存在") // 可以用contains判斷
// println(map0.get("a").get) // 如果key存在, 就會返回一個Some(值), 然后再用get函數(shù)取出值; 如果key不存在, 就會返回None; 總之代碼就不會直接拋異常了浆竭。
println(map0.getOrElse("a", "默認(rèn)值")) // 這個是最推薦用的函數(shù)
val map4 = map2 ++ mutable.Map("d" -> 4)
println(map2) // 不帶等于號的++, 就會返回新的Map, 而原先的Map是不變的!
println(map4)
// 遍歷Map方式1:
for ((k, v) <- map2) { // map中的每一個元素都是一元組,且是Tuple2類型的元組
println(k + "=" + v)
}
// 遍歷Map方式2:
for (k <- map2.keySet) { // 取出每一個key, 循環(huán)key,
println(k + "=" + map2(k))
}
// map的刪除
map0.remove("c")
map0 -= "c" // 即使key不存在也不會報錯
}
}
- 使用總結(jié):
- 如果能確定map有這個key惨寿,那么選擇map(key)是最好的邦泄,速度快;
- 如果我們不能確定map是否有這個key裂垦,而且有不同的業(yè)務(wù)邏輯在里面顺囊,使用map.contains()先判斷在處理。
3.如果只是簡單滴希望得到一個值缸废,使用map.getOrElse("key", "默認(rèn)值")包蓝。
Set
- scala默認(rèn)是使用的不可變集合,如果想用可變集合企量,需要引用包:mutable.Set测萎。
- 值無序且不可重復(fù)
略