Scala與Java的關(guān)系
Scala與Java的關(guān)系是非常緊密的??!
因?yàn)镾cala是基于Java虛擬機(jī),也就是JVM的一門編程語言。所有Scala的代碼,都需要經(jīng)過編譯為字節(jié)碼,然后交由Java虛擬機(jī)來運(yùn)行。
所以Scala和Java是可以無縫互操作的。Scala可以任意調(diào)用Java的代碼。所以Scala與Java的關(guān)系是非常非常緊密的。
安裝Scala
正常一直下一步的安裝
配置SCALA_HOME Path 中添加 %SCALA_HOME%\bin
Scala解釋器的使用
- REPL:Read(取值)-> Evaluation(求值)-> Print(打?。?> Loop(循環(huán))。scala解釋器也被稱為REPL,會(huì)快速編譯scala代碼為字節(jié)碼,然后交給JVM來執(zhí)行。
- 計(jì)算表達(dá)式:在scala>命令行內(nèi),鍵入scala代碼,解釋器會(huì)直接返回結(jié)果給你。如果你沒有指定變量來存放這個(gè)值,那么值默認(rèn)的名稱為res,而且會(huì)顯示結(jié)果的數(shù)據(jù)類型,比如Int、Double、String等等。
·例如,輸入1 + 1,會(huì)看到res0: Int = 2 - 內(nèi)置變量:在后面可以繼續(xù)使用res這個(gè)變量,以及它存放的值。
·例如,2.0 * res0,返回res1: Double = 4.0
·例如,"Hi, " + res0,返回res2: String = Hi, 2 - 自動(dòng)補(bǔ)全:在scala>命令行內(nèi),可以使用Tab鍵進(jìn)行自動(dòng)補(bǔ)全。
·例如,輸入res2.to,敲擊Tab鍵,解釋器會(huì)顯示出以下選項(xiàng),toCharArray,toLowerCase,toString,toUpperCase。因?yàn)榇藭r(shí)無法判定你需要補(bǔ)全的是哪一個(gè),因此會(huì)提供給你所有的選項(xiàng)。
·例如,輸入res2.toU,敲擊Tab鍵,直接會(huì)給你補(bǔ)全為res2.toUpperCase。
聲明變量
聲明val變量:可以聲明val變量來存放表達(dá)式的計(jì)算結(jié)果。
? 例如,val result = 1 + 1
? 后續(xù)這些常量是可以繼續(xù)使用的,例如,2 * result
? 但是常量聲明后,是無法改變它的值的,例如,result = 1,會(huì)返回error: reassignment to val的錯(cuò)誤信息。-
聲明var變量:如果要聲明值可以改變的引用,可以使用var變量。
例如,val myresult = 1,myresult = 2但是在scala程序中,通常建議使用val,也就是常量,因此比如類似于spark的大型復(fù)雜系統(tǒng)中,需要大量的網(wǎng)絡(luò)傳輸數(shù)據(jù),如果使用var,可能會(huì)擔(dān)心值被錯(cuò)誤的更改。
在Java的大型復(fù)雜系統(tǒng)的設(shè)計(jì)和開發(fā)中,也使用了類似的特性,我們通常會(huì)將傳遞給其他模塊 / 組件 / 服務(wù)的對象,設(shè)計(jì)成不可變類(Immutable Class)。在里面也會(huì)使用java的常量定義,比如final,阻止變量的值被改變。從而提高系統(tǒng)的健壯性(robust,魯棒性),和安全性。
指定類型:無論聲明val變量,還是聲明var變量,都可以手動(dòng)指定其類型,如果不指定的話,scala會(huì)自動(dòng)根據(jù)值,進(jìn)行類型的推斷。
? 例如,val name: String = null
? 例如,val name: Any = "leo"聲明多個(gè)變量:可以將多個(gè)變量放在一起進(jìn)行聲明。
? 例如,val name1, name2:String = null
? 例如,val num1, num2 = 100
數(shù)據(jù)類型與操作符
基本數(shù)據(jù)類型:Byte、Char、Short、Int、Long、Float、Double、Boolean。
? ·乍一看與Java的基本數(shù)據(jù)類型的包裝類型相同,但是scala沒有基本數(shù)據(jù)類型與包裝類型的概念,統(tǒng)一都是類。scala自己會(huì)負(fù)責(zé)基本數(shù)據(jù)類型和引用類型的轉(zhuǎn)換操作。
? ·使用以上類型,直接就可以調(diào)用大量的函數(shù),例如,1.toString(),1.to(10)。類型的加強(qiáng)版類型:scala使用很多加強(qiáng)類給數(shù)據(jù)類型增加了上百種增強(qiáng)的功能或函數(shù)。
? ·例如,String類通過StringOps類增強(qiáng)了大量的函數(shù),"Hello".intersect(" World")。
? ·例如,Scala還提供了RichInt、RichDouble、RichChar等類型,RichInt就提供了to函數(shù),1.to(10),此處Int先隱式轉(zhuǎn)換為RichInt,然后再調(diào)用其to函數(shù)基本操作符:scala的算術(shù)操作符與java的算術(shù)操作符也沒有什么區(qū)別,比如+、-、*、/、%等,以及&、|、^、>>、<<等。
? ·但是,在scala中,這些操作符其實(shí)是數(shù)據(jù)類型的函數(shù),比如1 + 1,可以寫做1.+(1)
? ·例如,1.to(10),又可以寫做1 to 10
? ·scala中沒有提供++、--操作符,我們只能使用+和-,比如counter = 1,counter++是錯(cuò)誤的,必須寫做counter += 1.
函數(shù)調(diào)用與apply()函數(shù)
函數(shù)調(diào)用方式:在scala中,函數(shù)調(diào)用也很簡單。
? ·例如,import scala.math._,sqrt(2),pow(2, 4),min(3, Pi)。
? ·不同的一點(diǎn)是,如果調(diào)用函數(shù)時(shí),不需要傳遞參數(shù),則scala允許調(diào)用函數(shù)時(shí)省略括號(hào)的,例如,"Hello World".distinctapply函數(shù)
? ·Scala中的apply函數(shù)是非常特殊的一種函數(shù),在Scala的object中,可以聲明apply函數(shù)。而使用“類名()”的形式,其實(shí)就是“類名.apply()”的一種縮寫。通常使用這種方式來構(gòu)造類的對象,而不是使用“new 類名()”的方式。
? ·例如,"Hello World"(6),因?yàn)樵赟tringOps類中有def apply(n: Int): Char的函數(shù)定義,所以"Hello World"(6),實(shí)際上是"Hello World".apply(6)的縮寫。
? ·例如,Array(1, 2, 3, 4),實(shí)際上是用Array object的apply()函數(shù)來創(chuàng)建Array類的實(shí)例,也就是一個(gè)數(shù)組。
條件控制與循環(huán)
if表達(dá)式的定義:在Scala中,if表達(dá)式是有值的,就是if或者else中最后一行語句返回的值。
? ·例如,val age = 30; if (age > 18) 1 else 0
? ·可以將if表達(dá)式賦予一個(gè)變量,例如,val isAdult = if (age > 18) 1 else 0
? ·另外一種寫法,var isAdult = -1; if(age > 18) isAdult = 1 else isAdult = 0,但是通常使用上一種寫法if表達(dá)式的類型推斷:由于if表達(dá)式是有值的,而if和else子句的值類型可能不同,此時(shí)if表達(dá)式的值是什么類型呢?Scala會(huì)自動(dòng)進(jìn)行推斷,取兩個(gè)類型的公共父類型。
? ·例如,if(age > 18) 1 else 0,表達(dá)式的類型是Int,因?yàn)?和0都是Int
? ·例如,if(age > 18) "adult" else 0,此時(shí)if和else的值分別是String和Int,則表達(dá)式的值是Any,Any是String和Int的公共父類型
? ·如果if后面沒有跟else,則默認(rèn)else的值是Unit,也用()表示,類似于java中的void或者null。例如,val age = 12; if(age > 18) "adult"。此時(shí)就相當(dāng)于if(age > 18) "adult" else ()。將if語句放在多行中:默認(rèn)情況下,REPL只能解釋一行語句,但是if表達(dá)式通常需要放在多行。
? ·可以使用{}的方式,比如以下方式,或者使用:paste和ctrl+D的方式。
if(age > 18) { "adult"
} else if(age > 12) "teenager" else "children"
語句終結(jié)符、塊表達(dá)式
默認(rèn)情況下,scala不需要語句終結(jié)符,默認(rèn)將每一行作為一個(gè)語句
一行放多條語句:如果一行要放多條語句,則必須使用語句終結(jié)符
? ·例如,使用分號(hào)作為語句終結(jié)符,var a, b, c = 0; if(a < 10) { b = b + 1; c = c + 1 }
? ·通常來說,對于多行語句,還是會(huì)使用花括號(hào)的方式
if(a < 10) {
? b = b + 1
? c = c + 1
}塊表達(dá)式:塊表達(dá)式,指的就是{}中的值,其中可以包含多條語句,最后一個(gè)語句的值就是塊表達(dá)式的返回值。
? ·例如,var d = if(a < 10) { b = b + 1; c + 1 }
輸入和輸出
print和println:print打印時(shí)不會(huì)加換行符,而println打印時(shí)會(huì)加一個(gè)換行符。
? ·例如,print("Hello World"); println("Hello World")printf:printf可以用于進(jìn)行格式化
? ·例如,printf("Hi, my name is %s, I'm %d years old.\n", "Leo", 30)readLine: readLine允許我們從控制臺(tái)讀取用戶輸入的數(shù)據(jù),類似于java中的System.in和Scanner的作用。
綜合案例:游戲廳門禁
val name = readLine("Welcome to Game House. Please tell me your name: ")
print("Thanks. Then please tell me your age: ")
val age = readInt()
if(age > 18) {
printf("Hi, %s, you are %d years old, so you are legel to come here!", name, age)
} else {
printf("Sorry, boy, %s, you are only %d years old. you are illegal to come here!", name, age)
}
循環(huán)
-
while do循環(huán):Scala有while do循環(huán),基本語義與Java相同。
var n = 10 while(n > 0) { println(n) n -= 1 } Scala沒有for循環(huán),只能使用while替代for循環(huán),或者使用簡易版的for語句
? ·簡易版for語句:var n = 10; for(i <- 1 to n) println(i)
? ·或者使用until,表式不達(dá)到上限:for(i <- 1 until n) println(i)
? ·也可以對字符串進(jìn)行遍歷,類似于java的增強(qiáng)for循環(huán),for(c <- "Hello World") print(c)-
跳出循環(huán)語句
? ·scala沒有提供類似于java的break語句。
? ·但是可以使用boolean類型變量、return或者Breaks的break函數(shù)來替代使用。import scala.util.control.Breaks._ breakable { var n = 10 for(c <- "Hello World") { if(n == 5) break; print(c) n -= 1 } }
高級for循環(huán)
-
多重for循環(huán):九九乘法表
for(i <- 1 to 9; j <- 1 to 9) { if(j == 9) { println(i * j) } else { print(i * j + " ") } }
if守衛(wèi):取偶數(shù)
for(i <- 1 to 100 if i % 2 == 0) println(i)for推導(dǎo)式:構(gòu)造集合
for(i <- 1 to 10) yield i
函數(shù)入門
函數(shù)的定義與調(diào)用
在Scala中定義函數(shù)時(shí),需要定義函數(shù)的函數(shù)名、參數(shù)、函數(shù)體。
我們的第一個(gè)函數(shù)如下所示:
def sayHello(name: String, age: Int) = {
if (age > 18) { printf("hi %s, you are a big boy\n", name); age }
else { printf("hi %s, you are a little boy\n", name); age
}
sayHello("leo", 30)
Scala要求必須給出所有參數(shù)的類型,但是不一定給出函數(shù)返回值的類型,只要右側(cè)的函數(shù)體中不包含遞歸的語句,Scala就可以自己根據(jù)右側(cè)的表達(dá)式推斷出返回類型。
在代碼塊中定義包含多行語句的函數(shù)體
單行的函數(shù):def sayHello(name: String) = print("Hello, " + name)
如果函數(shù)體中有多行代碼,則可以使用代碼塊的方式包裹多行代碼,代碼塊中最后一行的返回值就是整個(gè)函數(shù)的返回值。與Java中不同,不是使用return返回值的。
比如如下的函數(shù),實(shí)現(xiàn)累加的功能:
def sum(n: Int) = {
var sum = 0;
for(i <- 1 to n) sum += i
sum
}
遞歸函數(shù)與返回類型
如果在函數(shù)體內(nèi)遞歸調(diào)用函數(shù)自身,則必須手動(dòng)給出函數(shù)的返回類型。
例如,實(shí)現(xiàn)經(jīng)典的斐波那契數(shù)列:
9 + 8; 8 + 7 + 7 + 6; 7 + 6 + 6 + 5 + 6 + 5 + 5 + 4; ....
def fab(n: Int): Int = {
if(n <= 1) 1
else fab(n - 1) + fab(n - 2)
}
默認(rèn)參數(shù)
在Scala中,有時(shí)我們調(diào)用某些函數(shù)時(shí),不希望給出參數(shù)的具體值,而希望使用參數(shù)自身默認(rèn)的值,此時(shí)就定義在定義函數(shù)時(shí)使用默認(rèn)參數(shù)。
def sayHello(firstName: String, middleName: String = "William", lastName: String = "Croft") = firstName + " " + middleName + " " + lastName
如果給出的參數(shù)不夠,則會(huì)從作往右依次應(yīng)用參數(shù)。
Java與Scala實(shí)現(xiàn)默認(rèn)參數(shù)的區(qū)別
Java:
public void sayHello(String name, int age) {
if(name == null) {
name = "defaultName"
}
if(age == 0) {
age = 18
}
}
sayHello(null, 0)
Scala:
def sayHello(name: String, age: Int = 20) {
print("Hello, " + name + ", your age is " + age)
}
sayHello("leo")
帶名參數(shù)
在調(diào)用函數(shù)時(shí),也可以不按照函數(shù)定義的參數(shù)順序來傳遞參數(shù),而是使用帶名參數(shù)的方式來傳遞。
sayHello(firstName = "Mick", lastName = "Nina", middleName = "Jack")
還可以混合使用未命名參數(shù)和帶名參數(shù),但是未命名參數(shù)必須排在帶名參數(shù)前面。
sayHello("Mick", lastName = "Nina", middleName = "Jack")
變長參數(shù)
在Scala中,有時(shí)我們需要將函數(shù)定義為參數(shù)個(gè)數(shù)可變的形式,則此時(shí)可以使用變長參數(shù)定義函數(shù)。
def sum(nums: Int*) = {
var res = 0
for (num <- nums) res += num
res
}
sum(1, 2, 3, 4, 5)
使用序列調(diào)用變長參數(shù)
在如果想要將一個(gè)已有的序列直接調(diào)用變長參數(shù)函數(shù),是不對的。比如val s = sum(1 to 5)。此時(shí)需要使用Scala特殊的語法將參數(shù)定義為序列,讓Scala解釋器能夠識(shí)別。這種語法非常有用!一定要好好主意,在spark的源碼中大量地使用到了。
val s = sum(1 to 5: _*)
案例:使用遞歸函數(shù)實(shí)現(xiàn)累加
def sum2(nums: Int*): Int = {
if (nums.length == 0) 0
else nums.head + sum2(nums.tail: _*)
}
過程
在Scala中,定義函數(shù)時(shí),如果函數(shù)體直接包裹在了花括號(hào)里面,而沒有使用=連接,則函數(shù)的返回值類型就是Unit。這樣的函數(shù)就被稱之為過程。過程通常用于不需要返回值的函數(shù)。
過程還有一種寫法,就是將函數(shù)的返回值類型定義為Unit。
def sayHello(name: String) = "Hello, " + name
def sayHello(name: String) { print("Hello, " + name); "Hello, " + name }
def sayHello(name: String): Unit = "Hello, " + name
lazy值
在Scala中,提供了lazy值的特性,也就是說,如果將一個(gè)變量聲明為lazy,則只有在第一次使用該變量時(shí),變量對應(yīng)的表達(dá)式才會(huì)發(fā)生計(jì)算。這種特性對于特別耗時(shí)的計(jì)算操作特別有用,比如打開文件進(jìn)行IO,進(jìn)行網(wǎng)絡(luò)IO等。
import scala.io.Source._
lazy val lines = fromFile("C://Users//Administrator//Desktop//test.txt").mkString
即使文件不存在,也不會(huì)報(bào)錯(cuò),只有第一個(gè)使用變量時(shí)會(huì)報(bào)錯(cuò),證明了表達(dá)式計(jì)算的lazy特性。
val lines = fromFile("C://Users//Administrator//Desktop//test.txt").mkString
lazy val lines = fromFile("C://Users//Administrator//Desktop//test.txt").mkString
def lines = fromFile("C://Users//Administrator//Desktop//test.txt").mkString
異常
在Scala中,異常處理和捕獲機(jī)制與Java是非常相似的。
try {
throw new IllegalArgumentException("x should not be negative")
} catch {
case _: IllegalArgumentException => println("Illegal Argument!")
} finally {
print("release resources!")
}
try {
throw new IOException("user defined exception")
} catch {
case e1: IllegalArgumentException => println("illegal argument")
case e2: IOException => println("io exception")
}
數(shù)組操作之Array、ArrayBuffer以及遍歷數(shù)組
Array
在Scala中,Array代表的含義與Java中類似,也是長度不可改變的數(shù)組。此外,由于Scala與Java都是運(yùn)行在JVM中,雙方可以互相調(diào)用,因此Scala數(shù)組的底層實(shí)際上是Java數(shù)組。例如字符串?dāng)?shù)組在底層就是Java的String[],整數(shù)數(shù)組在底層就是Java的Int[]。
// 數(shù)組初始化后,長度就固定下來了,而且元素全部根據(jù)其類型初始化
val a = new Array[Int](10)
a(0)
a(0) = 1
val a = new Array[String](10)
// 可以直接使用Array()創(chuàng)建數(shù)組,元素類型自動(dòng)推斷
val a = Array("hello", "world")
a(0) = "hi"
val a = Array("leo", 30)
ArrayBuffer
在Scala中,如果需要類似于Java中的ArrayList這種長度可變的集合類,則可以使用ArrayBuffer。
// 如果不想每次都使用全限定名,則可以預(yù)先導(dǎo)入ArrayBuffer類
import scala.collection.mutable.ArrayBuffer
// 使用ArrayBuffer()的方式可以創(chuàng)建一個(gè)空的ArrayBuffer
val b = ArrayBuffer[Int]()
// 使用+=操作符,可以添加一個(gè)元素,或者多個(gè)元素
// 這個(gè)語法必須要謹(jǐn)記在心!因?yàn)閟park源碼里大量使用了這種集合操作語法!
b += 1
b += (2, 3, 4, 5)
// 使用++=操作符,可以添加其他集合中的所有元素
b ++= Array(6, 7, 8, 9, 10)
// 使用trimEnd()函數(shù),可以從尾部截?cái)嘀付▊€(gè)數(shù)的元素
b.trimEnd(5)
// 使用insert()函數(shù)可以在指定位置插入元素
// 但是這種操作效率很低,因?yàn)樾枰苿?dòng)指定位置后的所有元素
b.insert(5, 6)
b.insert(6, 7, 8, 9, 10)
// 使用remove()函數(shù)可以移除指定位置的元素
b.remove(1)
b.remove(1, 3)
// Array與ArrayBuffer可以互相進(jìn)行轉(zhuǎn)換
b.toArray
a.toBuffer
遍歷Array和ArrayBuffer
// 使用for循環(huán)和until遍歷Array / ArrayBuffer
// 使until是RichInt提供的函數(shù)
for (i <- 0 until b.length)
println(b(i))
// 跳躍遍歷Array / ArrayBuffer
for(i <- 0 until (b.length, 2))
println(b(i))
// 從尾部遍歷Array / ArrayBuffer
for(i <- (0 until b.length).reverse)
println(b(i))
// 使用“增強(qiáng)for循環(huán)”遍歷Array / ArrayBuffer
for (e <- b)
println(e)
數(shù)組常見操作
// 數(shù)組元素求和
val a = Array(1, 2, 3, 4, 5)
val sum = a.sum
// 獲取數(shù)組最大值
val max = a.max
// 對數(shù)組進(jìn)行排序
scala.util.Sorting.quickSort(a)
// 獲取數(shù)組中所有元素內(nèi)容
a.mkString
a.mkString(", ")
a.mkString("<", ",", ">")
// toString函數(shù)
a.toString
b.toString
使用yield和函數(shù)式編程轉(zhuǎn)換數(shù)組
// 對Array進(jìn)行轉(zhuǎn)換,獲取的還是Array
val a = Array(1, 2, 3, 4, 5)
val a2 = for (ele <- a) yield ele * ele
// 對ArrayBuffer進(jìn)行轉(zhuǎn)換,獲取的還是ArrayBuffer
val b = ArrayBuffer[Int]()
b += (1, 2, 3, 4, 5)
val b2 = for (ele <- b) yield ele * ele
// 結(jié)合if守衛(wèi),僅轉(zhuǎn)換需要的元素
val a3 = for (ele <- if ele % 2 == 0) yield ele * ele
// 使用函數(shù)式編程轉(zhuǎn)換數(shù)組(通常使用第一種方式)
a.filter(_ % 2 == 0).map(2 * _)
a.filter { _ % 2 == 0 } map { 2 * _ }
算法案例:移除第一個(gè)負(fù)數(shù)之后的所有負(fù)數(shù)
// 構(gòu)建數(shù)組
val a = ArrayBuffer[Int]()
a += (1, 2, 3, 4, 5, -1, -3, -5, -9)
// 每發(fā)現(xiàn)一個(gè)第一個(gè)負(fù)數(shù)之后的負(fù)數(shù),就進(jìn)行移除,性能較差,多次移動(dòng)數(shù)組
var foundFirstNegative = false
var arrayLength = a.length
var index = 0
while (index < arrayLength) {
if (a(index) >= 0) {
index += 1
} else {
if (!foundFirstNegative) { foundFirstNegative = true; index += 1 }
else { a.remove(index); arrayLength -= 1 }
}
}
算法案例:移除第一個(gè)負(fù)數(shù)之后的所有負(fù)數(shù)(改良版)
// 重新構(gòu)建數(shù)組
val a = ArrayBuffer[Int]()
a += (1, 2, 3, 4, 5, -1, -3, -5, -9)
// 每記錄所有不需要移除的元素的索引,稍后一次性移除所有需要移除的元素
// 性能較高,數(shù)組內(nèi)的元素遷移只要執(zhí)行一次即可
var foundFirstNegative = false
val keepIndexes = for (i <- 0 until a.length if !foundFirstNegative || a(i) >= 0) yield {
if (a(i) < 0) foundFirstNegative = true
i
}
for (i <- 0 until keepIndexes.length) { a(i) = a(keepIndexes(i)) }
a.trimEnd(a.length - keepIndexes.length)
Map與Tuple
創(chuàng)建Map
// 創(chuàng)建一個(gè)不可變的Map
val ages = Map("Leo" -> 30, "Jen" -> 25, "Jack" -> 23)
ages("Leo") = 31
// 創(chuàng)建一個(gè)可變的Map
val ages = scala.collection.mutable.Map("Leo" -> 30, "Jen" -> 25, "Jack" -> 23)
ages("Leo") = 31
// 使用另外一種方式定義Map元素
val ages = Map(("Leo", 30), ("Jen", 25), ("Jack", 23))
// 創(chuàng)建一個(gè)空的HashMap
val ages = new scala.collection.mutable.HashMap[String, Int]
訪問Map的元素
// 獲取指定key對應(yīng)的value,如果key不存在,會(huì)報(bào)錯(cuò)
val leoAge = ages("Leo")
val leoAge = ages("leo")
// 使用contains函數(shù)檢查key是否存在
val leoAge = if (ages.contains("leo")) ages("leo") else 0
// getOrElse函數(shù)
val leoAge = ages.getOrElse("leo", 0)
修改Map的元素
// 更新Map的元素
ages("Leo") = 31
// 增加多個(gè)元素
ages += ("Mike" -> 35, "Tom" -> 40)
// 移除元素
ages -= "Mike"
// 更新不可變的map
val ages2 = ages + ("Mike" -> 36, "Tom" -> 40)
// 移除不可變map的元素
val ages3 = ages - "Tom"
遍歷Map
// 遍歷map的entrySet
for ((key, value) <- ages) println(key + " " + value)
// 遍歷map的key
for (key <- ages.keySet) println(key)
// 遍歷map的value
for (value <- ages.values) println(value)
// 生成新map,反轉(zhuǎn)key和value
for ((key, value) <- ages) yield (value, key)
SortedMap和LinkedHashMap
// SortedMap可以自動(dòng)對Map的key的排序
val ages = scala.collection.immutable.SortedMap("leo" -> 30, "alice" -> 15, "jen" -> 25)
// LinkedHashMap可以記住插入entry的順序
val ages = new scala.collection.mutable.LinkedHashMap[String, Int]
ages("leo") = 30
ages("alice") = 15
ages("jen") = 25
Map的元素類型—Tuple
// 簡單Tuple
val t = ("leo", 30)
// 訪問Tuple
t._1
// zip操作
val names = Array("leo", "jack", "mike")
val ages = Array(30, 24, 26)
val nameAges = names.zip(ages)
for ((name, age) <- nameAges) println(name + ": " + age)