Scala Learn 1 Basic

Chap 0 前言

focus on:java

  1. Scala 的語法十分簡潔程序員

  2. Scala 運行在虛擬機之上, 可使用 java 的海量類庫和工具es6

  3. Scala 擁抱函數式編程的同時,並無廢棄面向對象算法

  4. Scala 既有動態語言那樣的靈活簡潔,同時有保留了靜態類型檢查的安全與執行效率編程

  5. Scala 既能處理腳本化的臨時任務,又能處理高併發場景下的分佈式互聯網大數據應用,可謂能縮能伸api

Chap 1 基礎

focus on:數組

  1. 使用 scala 解釋器安全

  2. 用 var 和 val 定義變量併發

  3. 數字類型oracle

  4. 使用操做符和函數

  5. 瀏覽 Scaladoc

1.1 Scala解釋器

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

1.2 聲明值和變量

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

1.3 經常使用類型

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

1.4 算術/操做符重載

+ - * / % 位 & | ^ >> << 都是完成一般的工做。
    只是有一點特別,這些操做符其實是方法。  
    a + b 實際上是  a.+(b)      + 是方法名。

Scala 並不會傻乎乎的 對方法名中使用非字母或數字 這種作法 帶有偏見

如 BigInt 類就定義了一個名爲 /% 的方法,該方法返回一個對偶 (商、餘數)
1.to(10) 也能夠寫成 1 to 10.

Scala 沒有提供 ++, -- 這種操做符。

1.5 調用函數和方法

除了方法以外,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

1.6 apply 方法

在 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)

1.7 Scaladoc

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

Chap 2 控制結構和函數

focus on:

  1. Scala 中,幾乎全部的構造出來語法結構都有值。(區別於Java語句沒有值)

  2. if、塊、 表達式 有值

  3. void 類型是 Unit

  4. 避免在函數定義中使用 return

  5. 注意別在函數式定義中漏掉了=。

  6. Scala 沒有受檢異常

2.1 條件表達式

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)}

2.2 塊表達式-賦值

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}

2.3 輸入和輸出

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。

2.4 循環

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 語句來退出循環。

2.5 for循環、for推導式

能夠以 變量 <- 表達式 的形式提供多個生成器,用分號將它們隔開。

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)

2.7 函數

定義函數,給出: 名稱、參數、函數體

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

2.8 默認參數和帶名參數

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>>>

2.9 變長參數

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 是 其餘元素的序列。

2.10 過程

不返回值函數的特殊表示法。 不建議使用

2.11 懶值

當 val 被聲明爲 lazy 時,它的初始化將被推遲,直到咱們首次對它取值。

lazy val words = scala.io.Source.fromFile("~/words").mkString

懶值對於開銷較大的初始化語句而言十分有用。

能夠把 懶值 當作是介於 val 和 def 的中間狀態。

說明 : 懶值並非沒有額外開銷。咱們每次訪問懶值,都會有一個方法被調用,而這個方法將會以線程安全的方式檢查該值是否已被初始化。

2.12 異常

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 { ... }

Chap 3 數組操做

focus on:

  1. 若 長度固定 則使用 Array, 若長度可能有變化則使用 ArrayBuffer。

  2. 提供初始值時不要使用 new

  3. 用 () 來訪問元素

  4. 用 for (elem <- arr) 來遍歷元素

  5. 用 for (elem <- arr if ...)...yield... 原數組轉型爲新數組

  6. Scala數組 和 Java數組 能夠互操做; 用 ArrayBuffer, 使用 scala.collection.JavaConversions 中的轉換函數

3.1 定長數組

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[]

3.2 變長數組

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)

3.3 遍歷數組和數組緩衝

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)

3.4 數組轉換

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)

3.5 經常使用算法

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

3.6 解讀 Scaladoc

對 Array類 的操做方法列在 ArrayOps 相關條目下。從技術上講,在數組上對用這些操做以前,數組都會被轉換成 ArrayOps對象

3.7 多維數組

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))

3.8 與 Java 的互操做

能夠引入 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)

Chap 4 映射和元組

focus on:

  1. Scala 有十分易用的語法來建立、查詢、遍歷映射

  2. 你須要從可變和不可變的映射中作出選擇

  3. 默認你獲得的是 哈希映射, 你也能夠指明要 樹形映射

  4. Scala映射 和 Java映射 之間來回切換

  5. 元組能夠用來彙集值

4.1 構造映射

不可變的映射

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)

4.2 獲取映射中的值

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  // 快捷寫法

4.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)

4.4 迭代映射

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)

4.5 已排序映射

操做映射的時候,你須要選定一個實現 : 哈希表 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

4.6 與 Java 的互操做

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互操做?

4.7 元組

映射是 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)

4.8 拉鍊操做

使用元組的緣由之一是把多個值綁在一塊兒,便於它們被一塊兒處理。

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)
相關文章
相關標籤/搜索