第一章 Scala基礎篇

1、Scala基礎語法

===sql

(一) 變量、類型、操做符

1.變量申明

●Java中:編程

//數據類型 變量名 = 值;
final int b = 2;
b = 23; //錯誤!!! final修飾的變量不可變
int a = 1;
a = 22;

●在Scala中:數組

//val/var 變量名:變量類型 = 變量值
val a:Int = 1
a =2 //錯誤!!!! val修飾的變量不能夠被從新賦值,相似於Java中的final
var b:Int = 1
b = 2

●說明數據結構

var聲明的變量能夠從新賦值app

val聲明的變量不能夠從新賦值,或稱之爲不可變變量/只讀變量。至關於java裏用final修飾的變量dom

●注意:函數式編程

Scala中變量聲明類型能夠省略,解析器會根據值進行推斷函數

Scala中語句最後不須要添加分號oop

val和var聲明變量時都必須初始化

爲了減小可變性引發的bug,應該儘量地使用不可變變量val。(推薦使用val)

若是想在變量名、類名等定義中使用語法關鍵字(保留字),能夠配合反引號:

val `val` = 123    //(符號爲鍵盤上Esc下面的鍵)

●Type關鍵字

Scala 裏能夠經過type 關鍵字來聲明類型。

type 至關於聲明一個類型別名:

// 把String 類型用S 代替
type S = String
val name: S = "bigdata"
println (name)

●懶值

應用場景

​ 當val被聲明爲lazy時,初始化將被推遲,只有當這個變量真正被使用到的時候,變量的賦值代碼纔會真正的執行

​ lazy適用於初始化開銷較大的場景

●代碼演示

package com.flyingAfish.baseTest

object VariableDemo {
  def main(args: Array[String]): Unit = {
    val name:String = "fizz"
    //name = "jack ma" //錯誤,val修飾的變量不能被從新賦值
    var money:Int = 8888
    money = 565//var修飾的變量能夠從新賦值

    val age = 18 //:Int 類型能夠省略,編譯器會自動推斷age的類型
    //age = "fizz" //錯誤,由於scala是強類型

    type str = String //type關鍵字能夠給類型起別名
    val animal:str = "fish"
  
    //當val被聲明爲lazy時,初始化將被推遲,只有當這個變量真正被使用到的時候,變量的賦值代碼纔會真正的執行
    //lazy適用於初始化開銷較大的場景
    val msg1 = init()
    println("我是按順序執行的")
    println(msg1)
    println("===============")
    lazy val msg2 = init()
    println("我先於init方法執行")
    println(msg2)
  }

  //定義一個方法,輸出一句話並返回一個字符串
  def init() ={
    println("init方法執行了")
    "msg"
  }
}

/*  init方法執行了
    我是按順序執行的
    msg
    ===============
    我先於init方法執行
    init方法執行了
    msg
*/

2.字符串

​ scala提供多種定義字符串的方式,咱們能夠根據須要來選擇最方便的定義方式。

●雙引號

val/var 變量名 = "字符串"

●三引號

​ 若是有大段的文本須要保存,就可使用三引號來定義字符串。例如:保存一大段的SQL語句。三個引號中間的全部字符串都將做爲字符串的值。

val/var 變量名 = """字符串1字符串2"""

●使用插值表達式

​ scala中,可使用插值表達式來定義字符串,有效避免大量字符串的拼接。

val/var 變量名 = s"${變量/表達式}字符串"
val/var 變量名 = s"""${變量/表達式}字符串"""

●代碼演示

package com.flyingAfish.baseTest

object StringDemo {
  def main(args: Array[String]): Unit = {
    val name = "fizz"
    val sql =
      """
        |select *           // | 豎條爲編譯器自動添加
        |from table
        |where name = fizz
      """.stripMargin       //.stripMargin 編譯器自動添加
    val sql2 =
      s"""                  //s 爲編譯器自動添加
        |select *
        |from table
        |where name = ${name}
      """.stripMargin       

    println(name)
    println(sql)
    println(sql2)
  }
}
/*
    fizz

    select *
    from table
    where name = fizz

    select *
    from table
    where name = fizz  
*/

3.數據類型

●數值類型

Scala和Java同樣,有多種數值類型Byte、Char、Short、Int、Long、Float、Double類型和1個Boolean類型。

Boolean true 或者 false
Byte 8位, 有符號
Short 16位, 有符號
Int 32位, 有符號
Long 64位, 有符號
Char 16位, 無符號
Float 32位, 單精度浮點數
Double 64位, 雙精度浮點數
String 其實就是由Char數組組成

●繼承體系

img

●Any

在scala中,全部的類,包括值類型,都最終繼承自一個統一的根類型Any,Any類是根節點

Any中定義了isInstanceOf、asInstanceOf方法,以及哈希方法等。AnyVal和AnyRef都擴展自Any類。

​ isInstanceOf:是否繼承自某類

​ asInstanceOf:強制類型轉換

●AnyVal-全部值類型的基類,全部的值都是類類型都是AnyVal的子類

- scala.Double

- scala.Float

- scala.Long

- scala.Int

- scala.Char

- scala.Short

- scala.Byte

上面是數字類型。

還包括scala.Unit 和 scala.Boolean 是非數字類型。

●AnyRef-是全部引用類型的基類。

​ 除了值類型,全部其餘類型都繼承自AnyRef

●Null

​ 是全部引用類型的子類型,Null類只有一個實例對象,null,相似於Java中的null引用。null能夠賦值給任意引用類型,可是不能賦值給值類型

●Nothing

是全部類型的子類型。Nothing類型沒有實例。它對於泛型結構是有用處的,舉例:

空列表Nil的類型是List[Nothing],它是List[T]的子類型,T能夠是任何類。

Nothing能夠做爲沒有正常返回值的方法的返回類型,很是直觀的告訴你這個方法不會正常返回,並且因爲Nothing是其餘任意類型的子類,他還能跟要求返回值的方法兼容。

●Unit

用來標識過程,也就是沒有明確返回值的函數。

因而可知,Unit相似於Java裏的void。Unit只有一個對象實例(),這個實例也沒有實質的意義。

●注意

1.Scala並不刻意區分基本類型 和 引用類型,因此這些類型都是對象,能夠調用相對應的方法。

2.每一種數值類型都有對應的Rich類型,如RichInt、RichChar等,爲基本類型提供了更多的有用操做。(重要

3.String直接使用的是java.lang.String類,另外在scala.collection.immutable.StringOps中還定義了更多的操做。在須要時String能隱式轉換爲StringOps,所以不須要任何額外的操做,String就可使用這些方法。

4.操做符

Scala中的+ - * / %等操做符的做用與Java同樣,位操做符 & | ^ >> <<也同樣。

●注意:

1.Scala中的操做符其實是方法

2.Scala中沒有++、--操做符,須要經過+=、-=來實現一樣的效果(由於++ -- 前置後置容易混淆)

3.+ - * / %是方法,那麼就能夠進行操做符重載,完成特殊的運算(也就是本身在類中定義+ - * / %方法表示特殊的運算)

●高級:

1)中置操做符,

//A操做符B 等同於 A.操做符(B) 
val a = 1
val b = 2
var c = a + b     
var d = a.+(b)  //等同與上式

2)後置操做符,

​ A操做符 等同於 A.操做符,若是操做符定義的時候不帶()則調用時不能加括號

math.random

3)前置操做符,

​ +、-、!、~等操做符 A等同於 A.unary_操做符。

var b = true
b = !b
b = b.unary_!   //等同與上式

4)賦值操做符,

​ A操做符=B 等同於 A=A操做符B

a += 1
a = a + 1   //等同與上式

●代碼演示

package com.flyingAfish.baseTest

object OperatorDemo {
  def main(args: Array[String]): Unit = {
    var a = 1
    var b = 2
    val result = a + b
    println(result)//3
    val result2 = a.+(b) //在Scala中運算符實際上是方法
    println(result2)//3
    //a++ //錯誤,在Scala中爲了不混淆,不支持++ --
    a += 1 //a = a + 1
    println(a)//2
  }

(二)循環判斷

1.塊表達式

定義變量時可使用 {} 包含一系列表達式,其中{}塊的最後一個表達式的值就是整個塊表達式的值。

●代碼演示

package com.flyingAfish.baseTest

object E_BlockDemo {
  def main(args: Array[String]): Unit = {
    var a = 1
    var b  =2
    var c = {
      a = a + b
      b = a + b
      var i = a + b
      i         //注意:{}塊表達式的最後一行是整個表達式的值
    }
    println(c)//8
  }
}

2.條件表達式

Scala條件表達式的語法和Java同樣,只是更加簡潔,且Scala中if else表達式是有返回值的

●注意:

Scala中沒有三元表達式

若是if或者else返回的類型不同,就返回Any類型

對於沒有返回值的,使用Unit,寫作(),至關於java中的void

●代碼演示

package com.flyingAfish.baseTest

object ConditionDemo {
  def main(args: Array[String]): Unit = {
    val sex1 = "male"
    val sex2 = "female"

    //if表達式有返回值
    val result1:String = if(sex1 == "male"){
      "男"
    }else{
      "女"
    }
    println(result1)

    val result2:String = if(sex1 == "male") "男" else "女"
    println(result2)

    //若是返回值類型不一致,返回Any
    val result3:Any = if(sex2 == "male"){
      "男"
    }else{
      0
    }
    println(result3)

    //()表示沒有返回值,即Unit,至關於Java中的void
    val result4:Unit = if(sex2 == "male"){
      println("男")
    }else{
      println("女")
    }
    println(result4)//()
  }
}

3.循環表達式

在scala中,可使用for循環和while循環,但通常推薦使用for表達式,由於for表達式語法更簡潔

●簡單for循環:

​ for (變量 <- 表達式/數組/集合) {循環體}

for(i <- 1 to 10){println(i)} //循環打印1~10

●嵌套for循環

​ for (變量1 <- 表達式/數組/集合; 變量2 <- 表達式/數組/集合) {循環體}

for(i <- 1 to 9; j <- 1 to 9){
     if(i >= j ) print(s"${j} * ${i} = ${j*i}")
     if(j == 9) println()
}

●守衛

​ for表達式中,能夠添加if判斷語句,這個if判斷就稱之爲守衛。咱們可使用守衛讓for表達式更簡潔。

​ for(i <- 表達式/數組/集合 if 表達式) {循環體}

for(i <- 1 to 10 if i % 3 == 0) println(i) //3,6,9

●for推導式(有返回值)

​ 在for循環體中,可使用yield表達式構建出一個集合,咱們把使用yield的for表達式稱之爲推導式

​ 便可以使用for推導式生成一個新的集合(一組數據)

//該for表達式會構建出一個集合
val res = for(i <- 1 to 10) yield i * 10 //10,20,30,40...

●注意:

​ while、for語句自己沒有值,即整個while語句的結果是Unit類型的()

var n = 1;
val result:unit = while(n <= 10){
    n += 1
}
println(result)
println(n)

●代碼演示

package com.flyingAfish.baseTest

object LoopDemo {
  def main(args: Array[String]): Unit = {
    //1 to 10 ===> [1,10]
    val res1 = 1 to 10 //Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    //1 until 10 ===> [1,10)
    val res2 = 1 until 10 //Range(1, 2, 3, 4, 5, 6, 7, 8, 9)
    //1 to 10 ===> [1,10],步長爲2
    val res3 = 1 to 10 by 2 //Range(1, 3, 5, 7, 9)
    println(res1)
    println(res2)
    println(res3)

    //1.簡單for循環
    for(i <- 1 to 10) println(i)

    println("===========分割線==========")
    //2.嵌套for循環--傳統寫法
    for(i <- 1 to 9){
      for(j <- 1 to 9){
        if(i >= j){
          print(s"${j} * ${i} = ${j * i} \t")
        }
      }
      println()
    }
    println("===========分割線==========")
    //2.嵌套for循環--Scala騷氣寫法
    for(i <- 1 to 9;j <- 1 to 9){
      if(i >= j) print(s"${j} * ${i} = ${j * i} \t")
      if(j == 9) println()
    }
    println("===========分割線==========")
    //3.守衛
    //需求打印1~10中3的倍數
    for(i <- 1 to 10){
      if(i % 3 == 0) println(i)
    }
    println("===========分割線==========")
    for(i <- 1 to 10 if(i % 3 == 0)) println(i)

    println("===========分割線==========")
    //4.for推導式
    //需求把1~10中的每個數擴大10倍造成一個新的集合
    //使用yield關鍵字能夠生成一個新的集合
    val col = for(i <- 1 to 10) yield i * 10
    println(col)//Vector(10, 20, 30, 40, 50, 60, 70, 80, 90, 100)

    println("===========分割線==========")
    //5.注意:while循環沒有返回值
    var n =1
    val result = while (n <= 100){
      n += 1
      n
   }
    println(n)//101
    println(result)//()
  }
}

(三)方法和函數

1.方法

def 方法名(參數名1: 參數類型1, 參數名2: 參數類型2) : 返回類型 = {方法體}

img

●語法細節

\1. 方法的返回值類型和return能夠不寫,編譯器能夠自動推斷出來

\2. 對於遞歸方法必須指定返回類型

\3. 若是方法沒有返回值,返回Unit類型(相似於void,也能夠不寫)

\4. 返回值類型有多種狀況則返回Any

\5. 帶有默認值參數的方法,調用時,能夠給定新值,也可使用默認值

\6. 能夠經過參數名來指定傳遞給哪個參數,這樣傳遞參數時就能夠不按照順序傳遞

\7. 方法沒有參數,調用時能夠省略(),若是定義時()省略,調用時則必須省略

\8. 可變參數使用 變量名: 類型* (相似Java的...

●代碼演示

package com.flyingAfish.baseTest

object MethodDemo {
  def main(args: Array[String]): Unit = {
    val result: Int = factorial(3)
    println(result)//6
    println(noReturnValue())//()
    //val resutl2: Int = haveDefaultParam(b=2)//102
    //val resutl3: Int = haveDefaultParam(a=1,b=2)//3
    //val resutl4: Int = haveDefaultParam(1,2)//3
    val resutl5: Int = haveDefaultParam(b=2,a=1)//3
    //println(resutl2)
    //println(resutl3)
    //println(resutl4)
    println(resutl5)

    noParam

    val sum: Int = multiParam(1,2,3,4,5)//15
    println(sum)
  }
  
  
  //def 方法名(參數名1:參數類型,參數名1:參數類型):返回值類型 = {方法體}
  //1.方法的返回值類型和return能夠不寫,編譯器能夠自動推斷出來
  def omitReturnValue() ={
     1
  }

  //2.對於遞歸方法,必須指定返回類型
  //需求:求n的階乘 ==> 10的階乘=1*2*3...*10 == 10 * 9 * 8 .....
  def factorial(n:Int):Int = {
    if (n == 1){
      1
    }else{
      n * factorial(n-1)
    }
  }

  //3.若是方法沒有返回值,返回Unit類型(相似於void,也能夠不寫)
  def noReturnValue():Unit={
    println("m3")
  }
  //4.返回值類型有多種狀況則返回Any或者不寫
  val sex = "male"
  def multiReturnValue():Any={
    if (sex == "male"){
      "男"
    }else{
      0
    }
  }
  //5.帶有默認值參數的方法,調用時,能夠給定新值,也可使用默認值
  //6.能夠經過參數名來指定傳遞給哪個參數,這樣傳遞參數時就能夠不按照順序傳遞
  def haveDefaultParam(a:Int=100,b:Int):Int={
    println("a="+a)
    println("b="+b)
    a + b
  }
  //7.方法沒有參數,調用時能夠省略(),若是定義時()省略,調用時則必須省略
  def noParam={
    println("m7")
  }
  //8.可變參使用 變量名:類型* (相似Java的...)
  //定義了一個方法能夠傳遞多個int值,並返回他們的和
  def multiParam(args:Int*):Int={
    var sum = 0
    for (i <- args){
      sum +=i
    }
    sum
  }
}

2.函數

●完整語法:

​ val函數名稱 :(參數類型)=>函數返回值類型 = (參數名稱:參數類型)=>函數體

val sum:(Int,Int)=>Int = (a:Int,b:Int)=>{a + b}

●簡寫語法:

​ val函數名稱 = (參數名稱:參數類型) => 函數體

val max = (a:Int,b:Int)=>{
    if(a > b) a
    else b
}

●符號解釋

​ = 表示將右邊的函數 賦給 左邊的變量

​ => 左面表示輸入參數名稱和類型,右邊表示函數的實現和返回值類型

3.方法和函數的區別

●方法:

​ 和以前學習Java時理解的方法同樣,是封裝了完成某些功能的代碼塊,所屬於某一個類或對象

●函數:

​ 在Scala中,函數是頭等公民,函數是一個對象,那麼既然是對象的話,函數就能夠賦值給變量 或者 看成參數被傳遞,還能夠 使用函數打點調用方法

​ Scala中函數繼承自FuctionN,帶有一個參數的函數的類型是function1,帶有兩個是function2,以此類推

●證實函數是對象

●函數是對象,能夠打點調方法

package com.flyingAfish.baseTest

object FunctionDemo {
  def main(args: Array[String]): Unit = {
    //val函數名稱 = (參數名稱:參數類型) => 函數體
    val add1 = (a:Int) => {a }
    val add2 = (a:Int,b:Int) => {a + b}
    val add3: (Int, Int, Int) => Int = (a:Int, b:Int, c:Int) => {a + b + c}
    println(add1)//<function1>
    println(add2)//<function2>
    println(add3)//<function3>
    
    //結論:函數是對象,有N個參數打印的時候就是functionN
    val str: String = add1.toString()//函數是對象,因此能夠調用方法
    println(str)//<function1>
    
    //函數通常用法
    println(add2(3,2))//5
  }
}

●函數能夠賦值給變量並將能夠看成參數進行傳遞

​ 定義一個函數,接收兩個參數,返回兩個數的和

​ 定義一個方法,接收兩個參數和一個函數,並在方法體中調用函數,將兩個參數傳遞給函數

package com.flyingAfish.baseTest

object FunctionDemo {
  def main(args: Array[String]): Unit = {
    //函數能夠賦值給變量並將能夠看成參數進行傳遞
    //定義一個函數,接收兩個參數,返回兩個數的和
    val add = (a:Int,b:Int) => a + b //證實了函數是對象,且函數能夠賦值給變量
    val result1: Int = operator(1,2,add) //證實了函數是對象,且函數能夠看成參數進行傳遞
    println(result1)//3

    //函數的好處:
    //能夠將咱們要進行的操做進行傳遞!!!
    //也就是函數式編程的核心思想:行爲參數化!!!
    val result2: Int = operator(1,2, (a,b)=> a*b)
    println(result2)

    println("=======================")
    //再來體會一下:行爲參數化!!!
    //val list = List(1,2,3,4,5)
    val list = 1 to 5
    //val f = (i:Int) => println(i)
    //list.foreach((i:Int) => println(i))
    //list.foreach(i => println(i))
    //list.foreach(println(_))
    list.foreach(println)
  }

  //定義一個方法,接收兩個參數和一個函數,並在方法體中調用函數,將兩個參數傳遞給函數
  def operator(a:Int,b:Int,fun:(Int,Int)=>Int) ={
    fun(a,b)
  }
}

●方法能夠轉換成函數

​ 證實方法無返回值也能夠調用

​ Java裏面方法無返回值不能調用

package com.flyingAfish.baseTest

object I_FunctionDemo4 {
    def main(args: Array[String]): Unit = {
        println(fizz()) //() 證實函數五返回值也能夠條用,打印的是空括號()
        println(fizz _) //下劃線 _能夠將方法變成函數 //<function0>
    }
    
    def fizz() = {
        
    }
}

4.總結

●定義方法:

​ def 方法名(參數名1: 參數類型1, 參數名2: 參數類型2) : 返回類型 = {方法體}

●定義方法簡寫法:

​ def 方法名(參數名1: 參數類型1, 參數名2: 參數類型2) = {方法體}

​ def 方法名 = {方法體}

●定義函數完整語法:

​ val函數名稱 :(參數類型)=>函數返回值類型 = (參數名稱:參數類型)=>函數體

●定義函數簡寫語法:

​ val函數名名稱 = (參數名稱:參數類型) => 函數體

img

●注意:

​ 嚴格的來講,函數與方法是不一樣的東西。定義方式上也有不少的區別

​ 可是在Scala中,函數自己是對象,方法能夠經過下劃線_轉換爲函數。

結論:在Scala中

​ 方法能夠轉換爲函數,函數本質上就是對象

​ 函數式編程的核心思想、靈魂所在:行爲參數化!

2、Scala經常使用數據結構/集合

(一)Scala集合分類和繼承體系

1.分類

●集合分類-按照數據結構特色分

​ Scala的集合都擴展自Iterable特質(先理解爲接口)

​ 有三大類:Seq序列(List)、Set、Map映射

●集合分類-按照可變和不可變分(注意:這裏的可變和不可變指的是集合的內容和長度,和以前的var/val有區別)

​ 大部分的集合Scala都同時提供了可變和不可變的版本。

​ 開發時建議Scala優先採用不可變集合(默認即爲不可變),知足不了需求是再使用可變集合

●可變集合和不可變集合相應的包爲:

​ 不可變集合:scala.collection.immutable (默認)

​ 可變集合: scala.collection.mutable

●注意

val和可變不可變

​ var和val指的是:變量可否被從新賦值

​ 集合可不可變指的是:集合長度或內容可不可變

對於數組:

​ 不可變數組Array:長度不可變,元素可變(定長數組)

​ 可變數組ArrayBuffer:長度和裏面的元素均可變(變長數組)(注意:Java裏面數組長度不可變)

對於其餘集合:

​ 不可變集合immutable:長度和內容都不可變,若是調用添加或者刪除方法,會產生新的集合,原集合不變

​ 可變集合mutable:長度和內容均可變

總結:

​ 開中優先使用不可變,若是知足不了需求再使用可變

2.繼承體系

●不可變集合(immutable )繼承層次:

img

●可變集合(mutable)繼承層次:

img

(二)數組

●不可變/定長數組:

val/var 變量名= new Array[T](數組長度)//scala.collection.immutable包下,不須要導包,默認就是
val/var 變量名 = Array(元素1, 元素2, 元素3...)

●可變/變長數組:

val/var 變量名 = ArrayBuffer[T]() //須要手動導入import scala.collection.mutable.ArrayBuffer包
val/var 變量名 = ArrayBuffer(元素1, 元素2, 元素3...)

●數組操做

指定分隔符 mkString

將數組轉換成數組緩衝 toBuffer(打印Buffer能夠看到數組內容)

根據索引獲取元素 ()

添加元素 +=

刪除元素 -=

追加一個數組到變長數組 ++=

往指定角標插入元素 insert

刪除指定角標的元素 remove

定長=>>變長 toBuffer

變長=>>定長 toArray

多維數組 Array.ofDimDouble

●遍歷數組

1.能夠for循環直接遍歷數組

2.能夠遍歷下標再根據下標獲取元素

3.回憶一下生成指定範圍的序列

0 to n 生成[0,n]

0 until n 生成[0,n)

●數組其餘經常使用方法

在Scala中,數組上的某些方法對數組進行相應的操做很是方便!

sum求和

max求最大值

min求最小值

sorted排序

reverse反轉

●代碼演示

package com.flyingAfish.baseTest
import scala.collection.mutable

object ArrayDemo {
  def main(args: Array[String]): Unit = {
    val arr: Array[Int] = Array(5,6,7,1,2,3,4,8,9)//不可變
    //不可變==>可變
    val arr2: mutable.Buffer[Int] = arr.toBuffer
    //可變==>不可變
    val arr3: Array[Int] = arr2.toArray

    //遍歷
    for(i <- arr) println(i)
    println("====================")
    //arr.foreach((i:Int)=>println(i))
    //arr.foreach(i=>println(i))
    //arr.foreach(println(_))
    arr.foreach(println)//行爲參數化
    println("====================")
    //逆序
    for(i <- arr.reverse) println(i)
    println("====================")
    //經過索引遍歷
    for(i <- 0 until arr.length) println(arr(i))

    //統計
    println(arr.sum)
    println(arr.max)
    println(arr.min)
    println(arr.reverse.mkString(","))
    println(arr.sorted.mkString(","))//按照默認的排序規則排序-升序
    println(arr.sortBy((i:Int) => -i).mkString(",")) //降序
    println(arr.sortWith((x:Int,y:Int) => x > y).mkString(","))//降序

  }
}

(三)元組

​ 元組也是能夠理解爲一個容器,能夠用來存放各類相同或不一樣類型的數據。例如:姓名,年齡,性別,出生年月。

元組的元素是不可變的

●建立元組

​ 使用括號來定義元組

val/var 元組 = (元素1, 元素2, 元素3....)
val animal = ("fish","cat","dog")
val world = ("fizz",34,animal,34.43)

​ 使用箭頭來定義元組(元組只有兩個元素)

val/var 元組 = 元素1->元素2 //對偶/二元組是最簡單的元組(k,v)
val animal: (String, String) = ("fizz", "dgo")
val dog: (String, Int) = "god" -> 3

●獲取元組中的值

//使用下劃線加腳標 ,例如 元組名._1  元組名._2 元組名._3
val animal: (String, String) = ("fizz", "dgo")
val dog: (String, Int) = "dog" -> 3
val name: String = animal._1
val age: Int = dog._2

注意:元組中的元素腳標是從1開始的

●將對偶(二元組)組成的數組轉換成映射(映射就至關於Java中的Map,後面會講)

將對偶/二元組的集合轉換成映射:

調用其toMap 方法

img

●遍歷

​ 能夠調用元組的productIterator方法獲取迭代器對象進行遍歷

●代碼演示

package com.flyingAfish.baseTest

object TupleDemo {
  def main(args: Array[String]): Unit = {
    //使用括號來定義元組
    //val/var 元組 = (元素1, 元素2, 元素3....)
    val t1: (String, Double, Int) = ("hadoop",3.14,110) //元組裏能夠存放不一樣類型的元素
    //使用箭頭來定義元組(元組只有兩個元素)
    //val/var 元組 = 元素1->元素2 //對偶/二元組是最簡單的元組(k,v)
    val t2: (String, Int) = "age"->18
    val t3 = ("age",18)
    println(t1)
    println(t2)
    println(t3)
    println(t1.getClass)
    println(t2.getClass)
    println(t3.getClass)

    //獲取元素
    println(t1._1)
    println(t1._2)
    println(t1._3)

    println("============")
    //val iterator: Iterator[Any] = t1.productIterator
    for(i <- t1.productIterator) println(i)

    //將二元組組成的集合轉成map
    val ts = Array(("jack",60),("tom",70),("rose",80))
    val map: Map[String, Int] = ts.toMap
    println(map)//Map(jack -> 60, tom -> 70, rose -> 80)
  }
}

(四)List

●高能預警

​ List操做的API方法和符號特別特別多,不用刻意去記,後續學習中會使用一些常見的,用的多了就掌握了!

●List介紹

​ 列表是scala中最重要的、也是最經常使用的數據結構。在scala中,也有兩種列表,一種是不可變列表、另外一種是可變列表

但都具有如下性質:

​ 能夠保存重複的值

​ 有前後順序

●不可變列表(默認)

​ import scala.collection.immutable._

​ 建立方式1.使用List(元素1, 元素2, 元素3, ...)來建立一個不可變列表

val/var 變量名 = List(元素1, 元素2, 元素3...)
val strings: List[String] = List("book","subject","car")
val book: List[Any] = List("English", 32, "chinese", 300)

​ 建立方式2.使用::方法建立一個不可變列表

val/var 變量名 = 元素1 :: 元素2 :: Nil 
val money: List[Int] = 34 :: 34 :: 344 :: Nil

注意:

​ 使用::拼接方式來建立列表,必須在最後添加一個Nil表示空列表

●可變列表

​ import scala.collection.mutable._

​ 建立方式1.使用ListBuffer元素類型建立空的可變列表

val/var 變量名 = ListBuffer[Int]()
val fizz: ListBuffer[Int] = ListBuffer[Int]()

​ 建立方式2.使用ListBuffer(元素1, 元素2, 元素3...)建立可變列表

val/var 變量名 = ListBuffer(元素1,元素2,元素3...)
val personName: ListBuffer[Any] = ListBuffer("kashke",34,"wangzida")

●head和tail

​ 在Scala中列表要麼爲Nil(Nil表示空列表)

​ 要麼是一個head元素加上一個tail列表。

//head爲列表第一個元素,tail爲列表除第一個元素外的元素列表
val list1 = List(1,2,3,4,5)
println(list1.head)//1
println(list1.tail)//List(2, 3, 4, 5)
val list = List(1)
println(list)//List(1)
println(list.head)//1
println(list.tail)//List()

●::操做符

:: 操做符是將給定的頭和尾建立一個新的列表,原列表不變  
:: 操做符是右結合的,如1 :: 5 :: 2 :: Nil至關於 1 :: (5 :: (2 :: Nil))   ==> List(1,5,2)

●可變列表操做

獲取/更改元素(使用括號訪問(索引值))
 添加元素(+=)
 追加一個列表(++=)
 刪除元素(-=)
 轉換爲List(toList)
 轉換爲Array(toArray)

●擴展:list其餘操做符(瞭解)

::  (x: A): List[A]                            在列表的頭部添加一個元素或列表
+:  (elem: A): List[A]                         在列表的頭部添加一個元素
:+  (elem: A): List[A]                         在列表的尾部添加一個元素
++  [B](that: GenTraversableOnce[B]): List[B]  從列表的尾部添加另一個列表
:::  (prefix: List[A]): List[A]                   在列表的頭部添加另一個列表

●擴展:等價操做(瞭解)

val left = List(1,2,3)
val right = List(4,5,6)
//如下操做等價
left ++ right      // List(1,2,3,4,5,6)
right.:::(left)     // List(1,2,3,4,5,6)
//如下操做等價
0 +: left    //List(0,1,2,3)
left.+:(0)   //List(0,1,2,3)
//如下操做等價
left :+ 4    //List(1,2,3,4)
left.:+(4)   //List(1,2,3,4)
//如下操做等價
0 :: left      //List(0,1,2,3)
left.::(0)     //List(0,1,2,3)

●代碼演示

package com.flyingAfish.baseTest

object ListDemo {
  def main(args: Array[String]): Unit = {
    //●不可變列表
    //val/var 變量名 = List(元素1, 元素2, 元素3...)
    val list1 = List(1,2,3,4,5)
    //val/var 變量名 = 元素1 :: 元素2 :: Nil
    val list2 = 1::2::Nil //List(1,2)

    //●可變列表
    //val/var 變量名 = ListBuffer[Int]()
    import scala.collection.mutable.ListBuffer
    val list3 = ListBuffer[Int]()
    //val/var 變量名 = ListBuffer(元素1,元素2,元素3...)
    val list4 = ListBuffer(1,2,3,4)
    list3.append(1,2,3)

    println(list1)
    println(list2)
    println(list3)//ListBuffer(1, 2, 3)
    println(list4)
    //List(1, 2, 3, 4, 5)
    //List(1, 2)
    //ListBuffer(1, 2, 3)
    //ListBuffer(1, 2, 3, 4)

    println(list1.head)//1
    println(list1.tail)//List(2, 3, 4, 5)
    val list = List(1)
    println(list)//List(1)
    println(list.head)//1
    println(list.tail)//List()

    println("============")
    list3.remove(1)//根據索引刪除
    println(list3)//ListBuffer(1, 3)
    list3 += 4
    list3 -= 1

    val list5 = list3.toList
    val list6 = list3.toArray

    val list7 = 0 +: list3
    println(list7)//ListBuffer(0, 3, 4)
    
    list7

    //遍歷
    for(i <- list3) println(i)
    list3.foreach(println)
  }
}

(五)隊列

●說明

​ 隊列數據存取符合先進先出的策略

​ 有 scala.collection.mutable.Queue 和 scala.collection.immutable.Queue

​ 通常來講咱們在開發中隊列一般使用可變隊列(特殊),其餘都推薦使用不可變

●常見操做

​ enqueue入隊/+=追加

​ dequeue出隊

●代碼演示

package com.flyingAfish.baseTest
import scala.collection.mutable

object DueueDemo {
  def main(args: Array[String]): Unit = {
    //隊列在開發中通常使用可變隊列
    val q = mutable.Queue[Int]()
    q.enqueue(1)
    q.enqueue(2)
    q.enqueue(3)
    q += 4
    q.+=(5)
    println(q)//Queue(1, 2, 3, 4 , 5)
    val i: Int = q.dequeue()
    println(i)//1
  }
}

(六)Set

●Set說明

Set表明一個沒有重複元素的無序集合;即沒法加入重複元素且不保證插入順序的。

●不可變Set(默認)

import scala.collection.immutable._

​ 1.建立一個空的不可變集,語法格式:

val/var 變量名 = Set[類型]()
val movie = Set[String]()

​ 2.給定元素來建立一個不可變集,語法格式:

val/var 變量名 = Set(元素1, 元素2, 元素3...)
val fresh = Set("apple","pear","apricot")

●可變Set

import scala.collection.mutable._

​ 格式相同,導包不一樣

Set操做

方法 描述
def +(elem: A): Set[A] 爲集合添加新元素,並建立一個新的集合,除非元素已存在
def -(elem: A): Set[A] 移除集合中的元素,並建立一個新的集合
def contains(elem: A): Boolean 若是元素在集合中存在,返回 true,不然返回 false。
def &(that: Set[A]): Set[A] 返回兩個集合的交集
def &~(that: Set[A]): Set[A] 返回兩個集合的差集
def ++(elems: A): Set[A] 合併兩個集合

●代碼演示

package com.flyingAfish.baseTest

object SetDemo {
  def main(args: Array[String]): Unit = {
    //●不可變Set(默認)
    //val/var 變量名 = Set(元素1, 元素2, 元素3...)
    val set1 = Set(1,2,3,4,5,6,7)

    //●可變Set
    //格式相同,導包不一樣
    //val/var 變量名 = Set[類型]()
    import scala.collection.mutable._
    val set2 = Set[Int]()
    set2.add(1)
    set2.add(2)
    set2.add(3)
    val set3 = set2 + 4
    val set4 = set2 - 1
    set2.remove(2)
    println(set2)//Set(1, 3)
    println(set3)//Set(1, 2, 3, 4)
    println(set4)//Set(2, 3)

    val set5 = set2 ++ set3 //並集
    println(set5)//Set(1, 2, 3, 4)

    val set6 = set3 & set2
    println(set6)//Set(1, 3)//交集

    val set7 = set3 &~ set2//差集
    println(set7)//Set(2, 4)

//遍歷和其餘集合同樣
  }
}

(七)Map

●說明

​ 在Scala中,把哈希表這種數據結構叫作映射類比Java的map集合

●不可變Map

import scala.collection.immutable.Map

​ 格式一:使用箭頭

val/var map = Map(鍵->值, 鍵->值, 鍵->值...)   // 推薦,可讀性更好
val hero = Map("fish"->"潮汐海靈","zeus"->"宙斯","baiqi"->"白起")

​ 格式二:利用元組

val/var map = Map((鍵, 值), (鍵, 值), (鍵, 值), (鍵, 值)...)
val subject = Map(("math","數學"),("English","英語"),("physics","物理"))

●可變Map

import scala.collection.mutable.Map

​ 格式相同,導包不一樣

●獲取值

map(鍵)
map.get(鍵)
map.getOrElse(鍵,默認值)//根據鍵取值,若是取到了則返回,沒取到返回指定的默認值

●修改值

map(鍵)=值

●增長值

map.put(鍵,值)

●代碼演示

package cn.fizz.collection

object MapDemo {
  def main(args: Array[String]): Unit = {
    //●不可變Map
    //●可變Map
    //格式相同,導包不一樣
    import scala.collection.mutable._
    //格式一:使用箭頭val/var map = Map(鍵->值, 鍵->值, 鍵->值...)   // 推薦,可讀性更好
    val map1 = Map("tom"->60,"rose"->70,"jack"->80,"zhaosi"->100)
    //格式二:利用元組val/var map = Map((鍵, 值), (鍵, 值), (鍵, 值), (鍵, 值)...)
    val map2 = Map(("tom",60),("rose",70),("jack",80),("zhaosi",100))
    map1.put("lily",90)
    map1.remove("tom")
    println(map1)
    println(map2)

    //根據key取值
    //Option是None和Some的父類
    //None表示空的,什麼都沒有
    //Some表示裏面有一個元素,在使用get就能夠取出來
    val op: Option[Int] = map1.get("zhaosi")
    println(op.get)//100

    //直接使用get方法很差,若是沒有指定的key,繼續操做可能會報錯
    //val op2: Option[Int] = map1.get("zaosi")
    //println(op2.get)

    val v: Int = map1.getOrElse("zaosi",0)
    println(v)//0

    val v2: Int = map1.getOrElse("zhaosi",0)
    println(v2)//100

    println("==========================")
    //遍歷
    //1.經過key
    for(k <- map1.keySet) println(map1(k))
    println("==========================")
    //2.直接遍歷value
    for(v <- map1.values) println(v)
    println("==========================")
    //3.經過元組
    for((k,v) <- map1) println(k+":"+v)
    println("==========================")
    //4.函數式的遍歷+模式匹配
    map1.foreach{
      case (k,v) => println(k+":"+v)
    }
  }
}

--------------------------------------------------------------------
-----------------------java版本-------------------------------------
--------------------------------------------------------------------

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class MapDemo {
    public static void main(String[] args){
        Map<String, Integer> map = new HashMap<>();
        map.put("k1",1);
        map.put("k2",2);
        map.put("k3",3);
        map.put("k4",4);

        Set<String> set = map.keySet();
        for (String k : set) {
            System.out.println(map.get(k));
        }
        Collection<Integer> values = map.values();
        for (Integer value : values) {
            System.out.println(value);
        }
        //開發的時候建議使用entrySet
        //由於entrySet拿出來的就是全部的kv,不須要在根據k去找v!!!
        Set<Map.Entry<String, Integer>> entries = map.entrySet();
        for (Map.Entry<String, Integer> entry : entries) {
            System.out.println(entry.getKey() + ":"+entry.getValue());
        }
    }
}
相關文章
相關標籤/搜索