focus on:java
Scala 的語法十分簡潔程序員
Scala 運行在虛擬機之上, 可使用 java 的海量類庫和工具es6
Scala 擁抱函數式編程的同時,並無廢棄面向對象算法
Scala 既有動態語言那樣的靈活簡潔,同時有保留了靜態類型檢查的安全與執行效率編程
Scala 既能處理腳本化的臨時任務,又能處理高併發場景下的分佈式互聯網大數據應用,可謂能縮能伸api
focus on:數組
使用 scala 解釋器安全
用 var 和 val 定義變量併發
數字類型oracle
使用操做符和函數
瀏覽 Scaladoc
scala> 8 * 5 + 2 res1: Int = 42 scala> 0.5 * res1 res4: Double = 21.0 scala> "Hello, " + res1 res5: String = Hello, 42 { String = java.lang.String }
scala 程序並非一個解釋器。
輸入的內容被快速地編譯成字節碼,而後這段字節碼交由 Java 虛擬機執行。
咱們稱之爲 : REPL
scala> res5.to // tab 補全 toByte toChar toDouble toFloat toInt toLong toShort toString scala> res5.toUpperCase res6: String = HELLO, 42
Scala 鼓勵使用 val, 除非你真的須要改變它。聲明值和變量不初始化會報錯。
注: 你不須要給出值和變量的類型,scala會根據初始化的值推斷出來。
scala> val answer = 8 * 5 + 2 answer: Int = 42 scala> answer * 0.5 res8: Double = 21.0
在必要的時候,你也但是指定類型
scala> val greeting: String = null greeting: String = null scala> val greeting: Any = "Hello" greeting: Any = Hello scala> val xmax, ymax = 100 xmax: Int = 100 ymax: Int = 100
Byte、Char、Short、Int、Long、Float、Double。和 Boolean。
與 Java 不一樣的是,這些類型是 類。
scala> 1.toString() res9: String = 1 scala> 1.to(10) res10: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
Scala不須要包裝類型。在基本類型和包裝類型之間轉換是 Scala 編譯器的工做。
Scala 用 java.lang.String 類來表示字符串。不過,它經過 StringOps 類給字符串追加了上百種操做。
舉例 intersect : scala> "Hello".intersect("World") res11: String = lo
在這個表達式中,java.lang.String 對象 "Hello" 被隱式地轉換成一個 StringOps 對象,接着 StringOps 類的 intersect 方法被應用。
一樣 Scala 還提供了 RichInt、RichDouble、RichChar 等 to 方法就是 RichInt 類中的方法。
還有 BigInt 和 BigDecimal類,用於任意大小(但有窮)的數字。這些類背後是 java.math.BigInteger 和 java.math.Bigdecimal,在scala中,他們用起來更方便,能夠用常規操做符來操做它們。
scala> val x: BigInt = 1234567890 x: BigInt = 1234567890 scala> x * x * x res13: scala.math.BigInt = 1881676371789154860897069000
+ - * / % 位 & | ^ >> << 都是完成一般的工做。 只是有一點特別,這些操做符其實是方法。 a + b 實際上是 a.+(b) + 是方法名。
Scala 並不會傻乎乎的 對方法名中使用非字母或數字 這種作法 帶有偏見
如 BigInt 類就定義了一個名爲 /% 的方法,該方法返回一個對偶 (商、餘數)
1.to(10) 也能夠寫成 1 to 10.
Scala 沒有提供 ++, -- 這種操做符。
除了方法以外,scala 還提供函數。相比 Java,在 Scala 中使用數學函數 (好比 : min 或 pow) 更爲簡單 ---- 你不須要從某個類調用它的靜態方法
scala> import scala.math._ 或 import math._ 說明: _ 通配符相似java * import scala.math._ scala> sqrt(2) 或者 math.sqrt(2) res15: Double = 1.4142135623730951 scala> pow(2, 4) res16: Double = 16.0 scala> min(3, Pi) res17: Double = 3.0
Scala 沒有靜態方法,
Scala有一個特性,叫作單例對象(singleton object)
一般一個類對應有一個 伴生對象 (companion object),其方法就跟 Java 中的靜態方法同樣。舉例來講,BigInt 類的 BigInt 伴生對象有一個生成指定位數的隨機素數的方法 probablePrime:
scala> BigInt.probablePrime(100, scala.util.Random) res33: scala.math.BigInt = 882882747840768533709728498879
說明 : 這裏的 Random 是一個單例隨機數生成器對象,而該對象是在 scala.util 包中定義的。這裏用單例對象比用類更好的爲數很少的場景之一。在Java中,爲每一個隨機數都構造出一個新的java.util.Random對象是一個常見的錯誤。
Scala 沒有參數且不改變當前對象的方法不帶圓括號。如 :
scala> "Hello".distinct res34: String = Helo
在 Scala 中,咱們一般都會使用相似函數調用的語法。
scala> "Hello"(4) res35: Char = o 至關於 C++ s[i], Java 的 s.charAt(i) 舉例來講 在 StringOps 類的文檔中,你會發現這樣一個方法 def apple(n: Int): Char "Hello"(4) 至關於 "Hello".apply(4)
若是去看 BigInt 伴生對象的文檔,就會看到讓你將字符串或數字轉換爲 BigInt 對象的 apply 方法。
scala> BigInt("12345") res36: scala.math.BigInt = 12345 scala> BigInt.apply("12345") res37: scala.math.BigInt = 12345 這個語句產生一個新的 BigInt 對象,不須要使用 new。 使用伴生對象apply方法是 Scala中 構建對象的經常使用手法 scala> Array(1, 4, 9, 16) res38: Array[Int] = Array(1, 4, 9, 16) scala> Array.apply(1, 4, 9, 16) res39: Array[Int] = Array(1, 4, 9, 16)
Java 程序員使用 Javadoc 瀏覽 Java API。
Scaladoc www.scala-lang.org/api 在線瀏覽 Scaladoc
www.scala-lang.org/download#api
注意每一個類名旁邊的 O 和 C,它們分別連接到對應的類 (C) 或 伴生對象 (O).
若是你想使用數值類型,記得看看 RichInt、RichDouble等。字符串看StringOps
數學函數 scala.math 包中
BigInt 有一個方法叫作 unary_-. 這就是你定義前置的負操做符 -x 的方式
標記爲 implicit 的方法對應的是自動(隱式)轉換。好比: BigInt 對象擁有在須要時自動被調用的由 int 和 long 轉換爲 BigInt 的方法。
方法能夠以函數做爲參數。 如 def count(p: (Char) => Boolean) : Int
調用相似方法時,你一般能夠一種很是緊湊的表示法給出函數定義。
scala> var s = "HelLo" s: String = HelLo scala> s.count(_.isUpper) res42: Int = 2
最後,當你偶爾遇到相似 StringOps 類中這樣的看上去幾乎無法一會兒理解的方法簽名時. 例以下狀況 :
def patch [B >: Char, That](from: Int, patch: GenSeq[B], replaced: Int) (implicit bf: CanBuildFrom[String, B, That]): That
別緊張,直接忽略便可,還有另外一個版本的 patch, 看上去容易講得通
def patch(from: Int, that: GenSeq[Char], replace: Int): StringOps[A]
若是你把 GenSeq[Char] 和 StringOps[A] 都當作 String 的話,這個方法從文檔理解起來就簡單多了。固然,在 REPL 中試用也很容易:
scala> "Harry".patch(1, "ung", 2) res43: String = Hungry
focus on:
Scala 中,幾乎全部的構造出來語法結構都有值。(區別於Java語句沒有值)
if、塊、 表達式 有值
void 類型是 Unit
避免在函數定義中使用 return
注意別在函數式定義中漏掉了=。
Scala 沒有受檢異常
scala> var x = -4 x: Int = -4 scala> val s = if (x > 0) 1 else -1 s: Int = -1 scala> if (x > 0) "positive" else -1 res0: Any = -1 {說明 : 類型不一樣,返回值爲公共超類型 Any} scala> if (x > 0) 1 res1: AnyVal = () scala> if (x > 0) 1 else () res2: AnyVal = () {說明 : 這兩條語句相同。()=Unit, (java void)}
scala> val k = {val dx = 2; val dy = 3; math.sqrt(dx * dx + dy * dy)} k: Double = 3.605551275463989 scala> x = y = 1 <console>:9: error: type mismatch; found : Unit required: Int x = y = 1 ^ {注意 : 賦值語句的值是 Unit}
scala> print("Answer: ") Answer: scala> print(42) 42 scala> println("Answer : " + 42) Answer : 42 scala> // C風格 的 printf scala> printf("Hello, %s! You are %d years old. \n", "fern", 28) Hello, fern! You are 28 years old.
從控制檯讀取 readLine, readInt, readDouble ...
scala> val name = readLine("Your name : ") warning: there was one deprecation warning; re-run with -deprecation for details Your name : name: String = Bean scala> val age = readInt() warning: there was one deprecation warning; re-run with -deprecation for details age: Int = 25 readDouble、readByte、readShort、readLong、 readFloat、readBoolean、readChar。
scala> var n = 3 n: Int = 3 scala> var r = 1 r: Int = 1 scala> :paste // Entering paste mode (ctrl-D to finish) while (n > 0) { r = r * n n -= 1 } // Exiting paste mode, now interpreting. scala> print(n) 0 scala> print(r) 6 scala> var n = 3 n: Int = 3 scala> 1 to n res13: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3) scala> for (i <- 1 to n) { | r = r*i | } scala> print(r) 36
說明 :
RichInt 類 這個 to 方法,返回 Range(區間)
在 for 循環的變量以前並無 val 或 var 的指定。該變量的類型是集合的原色類型。循環變量的做用域一直持續到循環結束。
scala> val s = "Hello" s: String = Hello scala> var sum = 0 sum: Int = 0 scala> for (i <- 0 until s.length) | sum += s(i) scala> sum res7: Int = 500 scala> var sum = 0 sum: Int = 0 你能夠直接遍歷字符序列,不須要使用下標 scala> for (ch <- "Hello") sum += ch scala> sum res9: Int = 500
說明 : Scala 並無直接提供 break 或 continue 語句來退出循環。
能夠以 變量 <- 表達式 的形式提供多個生成器,用分號將它們隔開。
scala> for (i <- 1 to 3; j <- 1 to 3) print ((10*i + j) + " ") 11 12 13 21 22 23 31 32 33
生成器能夠帶着守衛條件
scala> for (i <- 1 to 3; j <- 1 to 3 if i != j) print ((10*i + j) + " ") 12 13 21 23 31 32
注意 : if 以前沒有 分號
===
你可使用任意多的定義,引入能夠在循環中使用的變量 :
scala> for (i <- 1 to 3; from = 4 - i; j <- from to 3) print ((10*i + j) + " ") 13 22 23 31 32 33
循環體以 yield 開始,則該循環會構造出一個集合,每次迭代生成集合中的一個值
scala> for (i <- 1 to 10) yield i % 3 res12: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 0, 1, 2, 0, 1, 2, 0, 1)
這叫作 for推導式。 for推導式 生成的集合 與 它的第一個生成器是類型兼容的
scala> for (c <- "Hello"; i <- 0 to 1) yield (c + i).toChar res16: String = HIeflmlmop scala> for (i <- 0 to 1; c <- "Hello") yield (c + i).toChar res17: scala.collection.immutable.IndexedSeq[Char] = Vector(H, e, l, l, o, I, f, m, m, p) scala> 0 to 3 res20: scala.collection.immutable.Range.Inclusive = Range(0, 1, 2, 3)
定義函數,給出: 名稱、參數、函數體
scala> def abs(x: Double) = if (x >= 0) x else -x abs: (x: Double)Double scala> abs(-5) res22: Double = 5.0 scala> def fac(n: Int) = { | var r = 1 | for (i <- 1 to n) r = r * i | r | } fac: (n: Int)Int scala> fac(3) res23: Int = 6
咱們最好適應沒有 return 的日子,很快你就可使用大量匿名函數。return 至關於 函數版的 break。
對於遞歸函數,必須指定返回類型,Scala 不是 Haskell, Scala 猜想不出來
scala> def fact(n: Int): Int = if (n <= 0) 1 else n * fact(n-1) fact: (n: Int)Int scala> fact(4) res24: Int = 24
scala> def decorate(str: String, left: String = "[", right: String = "]") = left + str + right decorate: (str: String, left: String, right: String)String scala> decorate("Hello") res26: String = [Hello] scala> decorate(left = "<<<", str = "Hello", right = ">>>") res29: String = <<<Hello>>>
scala> def sum(args : Int*) = { | var result = 0 | for (arg <- args) result += arg | result | } sum: (args: Int*)Int scala> val s = sum(1, 4, 9, 16, 25) s: Int = 55
用 值的序列 調用是錯誤的。 告訴編譯器 當作 參數序列 處理
scala> val s = sum(1 to 5) <console>:8: error: type mismatch; found : scala.collection.immutable.Range.Inclusive required: Int val s = sum(1 to 5) ^ scala> val s = sum(1 to 5: _*) s: Int = 15
遞歸這樣解決
scala> def resurSum(args: Int*): Int = { | if (args.length == 0) 0 | else args.head + resurSum(args.tail: _*) | } resurSum: (args: Int*)Int scala> resurSum(1, 2, 3, 4, 5) res31: Int = 15
由於 序列的 head 是它的首個元素,tail 是 其餘元素的序列。
不返回值函數的特殊表示法。 不建議使用
當 val 被聲明爲 lazy 時,它的初始化將被推遲,直到咱們首次對它取值。
lazy val words = scala.io.Source.fromFile("~/words").mkString
懶值對於開銷較大的初始化語句而言十分有用。
能夠把 懶值 當作是介於 val 和 def 的中間狀態。
說明 : 懶值並非沒有額外開銷。咱們每次訪問懶值,都會有一個方法被調用,而這個方法將會以線程安全的方式檢查該值是否已被初始化。
Scala 的異常工做機制 和 Java / C++ 相似。
如 :
throw new IllegalArgumentException("x should not be negative")
當前運算被停止,運行時系統查找可接受 IllegalArgumentException 的異常處理器
和 Java 同樣,拋出的對象必須是 java.lang.Throwable 的子類。不過,與 Java 不一樣的是,Scala 沒有 「受檢」 異常 -- 你不須要聲明說函數或方法可能會拋出某種異常。
throw 表達式有特殊的類型 Nothing。 這在 if/else 表達式中有用。若是一個分支的類型是 Nothing,那麼 if/else 表達式的類型就是另外一個分支的類型。舉例來講, 考慮以下代碼
scala> var x = -1 x: Int = -1 scala> if (x >= 0) { | math.sqrt(x) | } else throw new IllegalArgumentException("x should not be negative") java.lang.IllegalArgumentException: x should not be negative ... 37 elided
第一個分支類型是 Double,第二個分支類型是 Nothing。 所以,if/else 表達式的類型是 Double。
捕獲異常的語法採用的是模式匹配的語法。
scala> try { | process(new URL("http://horstmann.com/fred-tiny.gif")) | } catch { | case _: MalformedURLException => println("Bad URL: " + url) | case ex: IOException => ex.printStackTrace() | }
和 Java 同樣,更通用的異常應該排在更具體的異常以後。
注意,若是你須要使用捕獲的異常對象,可使用 _ 來替代變量名
try / finally 語句讓你能夠釋放資源。
try { ... } finally { ... }
try { ... } catch { ... } finally { ... }
focus on:
若 長度固定 則使用 Array, 若長度可能有變化則使用 ArrayBuffer。
提供初始值時不要使用 new
用 () 來訪問元素
用 for (elem <- arr) 來遍歷元素
用 for (elem <- arr if ...)...yield... 原數組轉型爲新數組
Scala數組 和 Java數組 能夠互操做; 用 ArrayBuffer, 使用 scala.collection.JavaConversions 中的轉換函數
scala> val nums = new Array[Int](10) nums: Array[Int] = Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0) scala> val a = new Array[String](10) a: Array[String] = Array(null, null, null, null, null, null, null, null, null, null)
已經提供初始值就不須要 new.
scala> val s = Array("Hello", "World") s: Array[String] = Array(Hello, World) scala> s(0) = "Goodbye" scala> s res7: Array[String] = Array(Goodbye, World)
scala> Array(2,3,5,7) res8: Array[Int] = Array(2, 3, 5, 7)
Array(2,3,5,7) 在 JVM 中是 int[]
Java ArrayList -- C++ vector -- Scala ArrayBuffer
scala> import scala.collection.mutable.ArrayBuffer import scala.collection.mutable.ArrayBuffer scala> val b = ArrayBuffer[Int]() b: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer() scala> b += 1 res9: b.type = ArrayBuffer(1) scala> b += (1, 2, 3, 5) res11: b.type = ArrayBuffer(1, 1, 2, 3, 5) scala> b ++= Array(8, 13, 21) res12: b.type = ArrayBuffer(1, 1, 2, 3, 5, 8, 13, 21) scala> b.trimEnd(5) scala> b res15: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 1, 2)
在數組的尾端添加 或 刪除元素是一個高效的操做。
在任意位置插入或移除元素是低效。(以後的元素都須要平移)
scala> b.insert(2, 6) scala> b res15: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 1, 6, 2) scala> b.insert(2, 7, 8, 9) scala> b.remove(2) res17: Int = 7 scala> b.remove(2, 3) scala> b res19: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 1, 2) scala> b.toArray res20: Array[Int] = Array(1, 1, 2) scala> b.toBuffer res22: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1, 1, 2)
scala> val c = b.toBuffer c: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1, 1, 2) scala> c res24: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1, 1, 2) scala> val c = b.toArray c: Array[Int] = Array(1, 1, 2) scala> c res25: Array[Int] = Array(1, 1, 2)
for (i <- 0 until a.length) println(i + ": " + a(i)) 0 until 10 高帶 0.until(10) 0 until (a.length, 2) // Range(0, 2, 4, ...) 0 until (a.length).reverse for (elem <- a) println(elem)
scala> val a = Array(2, 3, 5, 7) a: Array[Int] = Array(2, 3, 5, 7) scala> val result = for (elem <- a) yield 2 * elem result: Array[Int] = Array(4, 6, 10, 14) // 從 數組緩衝 出發,也會獲得另外一個數組緩衝 scala> for (elem <- a if elem % 2 == 0) yield 2 * elem res26: Array[Int] = Array(4) scala> a res27: Array[Int] = Array(2, 3, 5, 7)
函數式編程
scala> a.filter(_ % 2 == 0).map(2 * _) res28: Array[Int] = Array(4)
考慮以下示例 :
給定一個整數的數組緩衝,咱們想要移除除第一個負數以外的全部負數。
1). 收集保留的下標
var first = true val indexs = for (i <- 0 until a.length if first || a(i) >= 0) yield { if (a(i) < 0) first = false; i }
2). 元素移動到該去的位置
for (j <- 0 until indexs.length) a(j) = a(indexs(j)) a.trimEnd(a.length - indexs.length)
cala> Array(1, 7, 2).sum res0: Int = 10 // ArrayBuffer the same scala> Array(1, 7, 2).min res1: Int = 1 scala> Array(1, 7, 2).max res2: Int = 7 scala> Array(1, 7, 2.5).max res4: Double = 7.0 scala> import scala.collection.mutable.ArrayBuffer import scala.collection.mutable.ArrayBuffer scala> ArrayBuffer("Mary", "had", "little", "lamb").max res9: String = little
sorted 方法將 Array or ArrayBuffer 排序並返回通過排序的 Array or ArrayBuffer
不改變原數組,產生新數組
scala> val b = ArrayBuffer(1, 7, 2, 9).sorted b: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 7, 9) scala> val b = ArrayBuffer(1, 7, 2, 9).sortWith(_>_) b: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(9, 7, 2, 1)
改變原數組
scala> val a = Array(1, 7, 2, 9) a: Array[Int] = Array(1, 7, 2, 9) scala> scala.util.Sorting.quickSort(a) scala> a res11: Array[Int] = Array(1, 2, 7, 9)
對於 min, max 和 quickSort 方法,元素類型必須支持比較操做, 這包括了數字、字符串以及其餘帶有 Ordered 特質的類型。
顯示 Array 或 ArrayBuffer 的內容,用 mkString
scala> a.mkString res12: String = 1279 scala> a.mkString(",") res13: String = 1,2,7,9 scala> a.mkString("<", ",", ">") res14: String = <1,2,7,9> scala> a.toString res15: String = [I@6691eb1e
對 Array類 的操做方法列在 ArrayOps 相關條目下。從技術上講,在數組上對用這些操做以前,數組都會被轉換成 ArrayOps對象
Double 的二維數組類型爲 Array[Array[Double]]. 構造用 ofDim 方法。
scala> val matrix = Array.ofDim[Double](3, 4) matrix: Array[Array[Double]] = Array(Array(0.0, 0.0, 0.0, 0.0), Array(0.0, 0.0, 0.0, 0.0), Array(0.0, 0.0, 0.0, 0.0)) scala> matrix(1)(2) = 42 scala> matrix res19: Array[Array[Double]] = Array(Array(0.0, 0.0, 0.0, 0.0), Array(0.0, 0.0, 42.0, 0.0), Array(0.0, 0.0, 0.0, 0.0))
建立不規則數組
scala> val triangle = new Array[Array[Int]](10) triangle: Array[Array[Int]] = Array(null, null, null, null, null, null, null, null, null, null) scala> for (i <- 0 until triangle.length) | triangle(i) = new Array[Int](i+1) scala> triangle res21: Array[Array[Int]] = Array(Array(0), Array(0, 0), Array(0, 0, 0), Array(0, 0, 0, 0), Array(0, 0, 0, 0, 0), Array(0, 0, 0, 0, 0, 0), Array(0, 0, 0, 0, 0, 0, 0), Array(0, 0, 0, 0, 0, 0, 0, 0), Array(0, 0, 0, 0, 0, 0, 0, 0, 0), Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
能夠引入 scala.collection.JavaConversions 裏的隱式轉換方法。
java.lang.ProcessBuilder類 有一個以 List<String> 爲參數的構造器
import scala.collection.JavaConversions.bufferAsJavaList import scala.collection.mutable.ArrayBuffer scala> val command = ArrayBuffer("ls", "-al", "/home/data0") command: scala.collection.mutable.ArrayBuffer[String] = ArrayBuffer(ls, -al, /home/data0) // Scala 到 Java 的轉換 scala> val pb = new ProcessBuilder(command) pb: ProcessBuilder = java.lang.ProcessBuilder@467eb8eb
import scala.collection.mutable.Buffer import scala.collection.JavaConversions.asScalaBuffer scala> val cmd: Buffer[String] = pb.command() // Java到Scala轉換 cmd: scala.collection.mutable.Buffer[String] = ArrayBuffer(ls, -al, /home/data0) scala> command res25: scala.collection.mutable.ArrayBuffer[String] = ArrayBuffer(ls, -al, /home/data0)
focus on:
Scala 有十分易用的語法來建立、查詢、遍歷映射
你須要從可變和不可變的映射中作出選擇
默認你獲得的是 哈希映射, 你也能夠指明要 樹形映射
Scala映射 和 Java映射 之間來回切換
元組能夠用來彙集值
不可變的映射
scala> val scores = Map("Alice" -> 10, "Bob" -> 3, "Cindy" -> 8) scores: scala.collection.immutable.Map[String,Int] = Map(Alice -> 10, Bob -> 3, Cindy -> 8)
可變的映射
scala> val scores = scala.collection.mutable.Map("Alice" -> 10, "Bob" -> 3, "Cindy" -> 8) scores: scala.collection.mutable.Map[String,Int] = Map(Bob -> 3, Alice -> 10, Cindy -> 8)
new 空映射
scala> val scores = new scala.collection.mutable.HashMap[String, Int] scores: scala.collection.mutable.HashMap[String,Int] = Map()
Scala 中,映射是對偶的集合。
scala> "Alice"->10 res26: (String, Int) = (Alice,10) scala> val scores = Map(("Alice", 10), ("Bob", 3)) scores: scala.collection.immutable.Map[String,Int] = Map(Alice -> 10, Bob -> 3)
scala> val bobsScore = scores("Bob") bobsScore: Int = 3 scala> val bobsScore = if (scores.contains("Bob")) scores("Bob") else 0 bobsScore: Int = 3 scala> val bobsScore = if (scores.contains("Bob")) scores("Bobo") else 0 java.util.NoSuchElementException: key not found: Bobo at scala.collection.MapLike$class.default(MapLike.scala:228) at scala.collection.AbstractMap.default(Map.scala:59) at scala.collection.MapLike$class.apply(MapLike.scala:141) at scala.collection.AbstractMap.apply(Map.scala:59) ... 33 elided scala> val bobsScore = if (scores.contains("Bobo")) scores("Bob") else 0 bobsScore: Int = 0 scala> val bobsScore = scores.getOrElse("Bob", 0) bobsScore: Int = 3 // 快捷寫法
scala> val scores = scala.collection.mutable.Map("Alice" -> 10, "Bob" -> 3, "Cindy" -> 8) scores: scala.collection.mutable.Map[String,Int] = Map(Bob -> 3, Alice -> 10, Cindy -> 8) scala> scores("Bob")=10 scala> val bobsScore = scores.getOrElse("Bob", 0) bobsScore: Int = 10 scala> scores("Kevin")=100 scala> scores res30: scala.collection.mutable.Map[String,Int] = Map(Bob -> 10, Kevin -> 100, Alice -> 10, Cindy -> 8) scala> scores += ("Bob"->90, "Fred"->7) res31: scores.type = Map(Bob -> 90, Kevin -> 100, Fred -> 7, Alice -> 10, Cindy -> 8) scala> scores res32: scala.collection.mutable.Map[String,Int] = Map(Bob -> 90, Kevin -> 100, Fred -> 7, Alice -> 10, Cindy -> 8) scala> scores -= "Alice" res33: scores.type = Map(Bob -> 90, Kevin -> 100, Fred -> 7, Cindy -> 8) scala> scores res34: scala.collection.mutable.Map[String,Int] = Map(Bob -> 90, Kevin -> 100, Fred -> 7, Cindy -> 8) scala> scores -= "Alice00" res36: scores.type = Map(Bob -> 90, Kevin -> 100, Fred -> 7, Cindy -> 8)
scala> scores.keySet res40: scala.collection.Set[String] = Set(Bob, Kevin, Fred, Cindy) scala> scores.values res46: Iterable[Int] = HashMap(90, 100, 7, 8) scala> for ((k, v) <- scores) yield { print (k, v) } (Bob,90)(Kevin,100)(Fred,7)(Cindy,8)res42: scala.collection.mutable.Iterable[Unit] = ArrayBuffer((), (), (), ()) scala> for ((k, v) <- scores) yield (v, k) res45: scala.collection.mutable.Map[Int,String] = Map(8 -> Cindy, 100 -> Kevin, 7 -> Fred, 90 -> Bob)
操做映射的時候,你須要選定一個實現 : 哈希表 or 平衡樹. default hashtable
獲得一個不可變的樹形映射,而不是哈希映射
scala> val scores = scala.collection.immutable.SortedMap("Alice" -> 10, "Fred" -> 7, "Bob" -> 3, "Cindy" -> 8) scores: scala.collection.immutable.SortedMap[String,Int] = Map(Alice -> 10, Bob -> 3, Cindy -> 8, Fred -> 7)
可變的樹形映射,選擇 Java 的 TreeMap。
按照插入順序訪問全部的鍵,使用 scala 的 LinkedHashMap
Java映射 轉換爲 Scala映射
scala> import scala.collection.JavaConversions.mapAsScalaMap import scala.collection.JavaConversions.mapAsScalaMap scala> val scores: scala.collection.mutable.Map[String, Int] = new java.util.TreeMap[String, Int] scores: scala.collection.mutable.Map[String,Int] = Map()
java.util.Properties 到 Map[String, String] 的轉換
scala> import scala.collection.JavaConversions.propertiesAsScalaMap import scala.collection.JavaConversions.propertiesAsScalaMap scala> val props: scala.collection.Map[String, String] = System.getProperties() props: scala.collection.Map[String,String] = Map(env.emacs -> "", java.runtime.name -> Java(TM) SE Runtime Environment, sun.boot.library.path -> /Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/jre/lib, java.vm.version -> 24.79-b02, user.country.format -> CN, gopherProxySet -> false, java.vm.vendor -> Oracle Corporation, java.vendor.url -> http://java.oracle.com/, path.separator -> :, java.vm.name -> Java HotSpot(TM) 64.Bit Server VM, file.encoding.pkg -> sun.io, user.country -> US, sun.java.launcher -> SUN_STANDARD, sun.os.patch.level -> unknown, java.vm.specification.name -> Java Virtual Machine Specification, user.dir -> /Users/hp, java.runtime.version -> 1.7.0_79-b15, java.awt.graphicsenv -> sun.awt.CGraphicsEnvironment, java.endorsed.dirs -> /Library/Java/JavaVirtual...
Scala映射 傳遞給 預期 Java映射 的方法,提供相反的隱式轉換
import scala.collection.JavaConversions.mapAsJavaMap import java.awt.font.TextAttribute._ scala> val attrs = Map(FAMILY -> "Serif", SIZE -> 12) attrs: scala.collection.immutable.Map[java.awt.font.TextAttribute,Any] = Map(java.awt.font.TextAttribute(family) -> Serif, java.awt.font.TextAttribute(size) -> 12) 如下方法預期一個 java映射 scala> val font = new java.awt.Font(attrs) font: java.awt.Font = java.awt.Font[family=Serif,name=Serif,style=plain,size=12] scala> font res47: java.awt.Font = java.awt.Font[family=Serif,name=Serif,style=plain,size=12] scala> attrs res48: scala.collection.immutable.Map[java.awt.font.TextAttribute,Any] = Map(java.awt.font.TextAttribute(family) -> Serif, java.awt.font.TextAttribute(size) -> 12)
不是很明白 java互操做?
映射是 key/value 對偶 的集合。 對偶 是 元組 tuple 最簡單的形態。
scala> val t = (1, 3.14, "Hello") t: (Int, Double, String) = (1,3.14,Hello) scala> val second = t._2 second: Double = 3.14 scala> val (first, second, _) = t first: Int = 1 second: Double = 3.14
元組的下標從 1 開始。
元組能夠用於函數返回不止一個值的狀況。舉例來講, StringOps 的 partition 方法返回的是一對字符串,分別包含了知足某個條件和不知足該條件的字符
scala> val y1 = "New York".partition(_.isUpper) y1: (String, String) = (NY,ew ork)
使用元組的緣由之一是把多個值綁在一塊兒,便於它們被一塊兒處理。
scala> val symbols = Array("<", "-", ">") symbols: Array[String] = Array(<, -, >) scala> val counts = Array(2, 10, 2) counts: Array[Int] = Array(2, 10, 2) scala> val pairs = symbols.zip(counts) pairs: Array[(String, Int)] = Array((<,2), (-,10), (>,2)) scala> for ((s, n) <- pairs) Console.print(s * n) <<---------->>
用 toMap 方法能夠將對偶的集合轉換成映射
scala> val pairs = symbols.zip(counts).toMap pairs: scala.collection.immutable.Map[String,Int] = Map(< -> 2, - -> 10, > -> 2)