1. 程式人生 > >Scala學習(一) 快速入門

Scala學習(一) 快速入門

學習Spark就要學習Scala,今天開始快速學習Scala.直接在這裡做筆記了.

1 Scala基礎與語法

1.1 基本資料型別

8中常見資料型別:Byte,Char,Short,Int,Long,Float,DoubleBoolean. 這裡的FloatDouble 的具體區別就是 :

浮點數如0.0f或者0.0F,若沒有 f 字尾則是Double變數

String也是基本資料型別,它屬於java.lang 包,這個包是預設匯入的.

1.2 Scala變數宣告

Scala通過 varval 來宣告變數.其中 var 是可以重新賦值的,和普通變數沒啥區別,但是val

賦值一次後不能再賦值,相當於java中的final修飾的變數.

舉個栗子,以val 為例,var 差不多

scala> val i=10
i: Int =10 
scala>println(i)
10
scala>i=11  //i是不可變的,所以會報錯
<console>:8:error reassignment to val
    i=10
     ^
scala> val a,b = 1f //scala允許一次定義多個變數,這裡定義兩個Float型別的
a:Int = 10
b:Int = 10

//在定義的時候可以指定資料型別
scala> val
i:Int =10 i:Int = 10

1.3 算術操作符介紹

這個和c或者java沒區別,直接上例子

//算術運算子=-*/
scala> 1+2 //在scala中+-*/也是物件的函式,所以也可以這麼呼叫1.+(2)
res0:Int=3

//關係運算符== > >= ...
scala>3==2
res1:Boolean = false

//邏輯運算子 && || ! 
scala> true&&false
res2:Boolean:false

//位運算子 & | ^ (與/或/異或)
scala> 0^1
res3:1
//賦值運算子 += -= <<= ... //總的來說就是 A op B ==> A= A op B scala>var a=3 a:Int=3 scala>a+=2 5

1.4 條件語句

scala中的條件語句是有返回值的,可以將其賦值給某個變數,類似於三目運算子.

if(條件) x else y

當然也可以給x ,y加上花括號

if (條件) {
...
}else {
...
}

舉個例子

scala> val i=if(3>1) 3 else 1
i:Int=3 //3賦值給了變數i

scala>if(x<20){
|   println("This is if test")
|}
This is if test

scala中的條件語句在for迴圈中或match 模式匹配中可以成為 守衛 看下面講迴圈的例子.

1.5 迴圈

與java c一樣的迴圈結構 for ,while,do-while等,但是具體寫起來還是有差別的

1.5.1 for 迴圈

for (var <- set)
{
...
}

舉個例子

scala>for(i<- 1 to 10) print(i+" ") //1 to 10 生成Range(1,2,..,10)
1 2 3 4 5 6 7 8 9 10

//1 until 10 生成的不包含尾部,生成的是(1,2,...,9)
scala>for(i<- 1 until 10) print(i+" ")
1 2 3 4 5 6 7 8 9

//for 迴圈中使用守衛
scala>for(i<- 1 to 10 if i%2==0)print(i+" ")
2 4 6 8 10
scala>for(i<- 1 to 10 if i%2==0;if i!=2)print(i+" ") //多個過濾條件用分號隔開.
4 6 8 10

for 迴圈中使用守衛


scala>for(i<- 1 to 10 if i%2==0)print(i+" ")
2 4 6 8 10
scala>for(i<- 1 to 10 if i%2==0;if i!=2)print(i+" ") //多個過濾條件用分號隔開.
4 6 8 10

for迴圈巢狀,這裡和一般的java中的巢狀不一樣.

scala>for(i<- 1 to 5;j<- 1 to 5 if i%2==0)print(i*j+" ")
2 3 4 6 8 10 12 16 20 

利用yield關鍵字返回一個新集合

scala>val v1 = for(i<- 1 to 5)yield i
v1:Scala.collection.immutable.IndexSeq[Int]= Vector(1,2,3,4,5)

1.5.2 while 迴圈

while(條件表示式){
...
}

直接上例子

scala> while(i<=5){
     | i +=1
     | print(i+ " ")
     | }
2 3 4 5 6 

注意的是,在forwhile中都沒有用到breakcontinue,這是因為在scala中沒有break和continue兩個關鍵字,continue可以通過if條件語句來控制是否要向下執行,而break語句在scala中有特殊的實現

import scala.util.control.Breaks._
import scala.util.Random
object ControlStatementBreak{
    def main(args:Array[String]){
        breakable{
        while(true){
            val r = new Random()
            val i= r.nextInt(10)
            println("i=="+i)
            if(i==5){
            break
            }
        }
    }
}
}
/*這段程式碼首先import 了 scala.util.control.Breaks._ ,這樣就可以使用
breakable和break語句了.在while語句外面用breakable語句塊包圍了,然後在需
要break的地方呼叫break方法,這裡的break 不是關鍵字,而是一個scala方法,這個
方法會丟擲異常從而中斷迴圈
*/

1.5.3 do-while 迴圈

這個和while類似,和java中do-while和while的迴圈的區別一樣,所以不再贅述.
語法:

do{
迴圈體
}(條件表示式)

嚴格的來說, scala中的for被成為表示式,它和if一樣,可以返回結果,而while或者do-while型別的就是迴圈結構,它們返回的結構為Unit型別.

1.6 異常控制

分為捕獲異常和丟擲異常

1.6.1 丟擲異常使用關鍵字 throw

例如

throw new IlleagalArgumentException

1.6.2 捕獲異常

例如:

try{
...
} catch {
    case ex:NullPointException=>...
    case ...
}
finally{//finally語句不一定會有,如果有一定會執行
    println("通常用來釋放資源")
}

舉個例子(檔案讀取)

object ReadFileTest{
    def main(args:Array[String]){
    try{
        val file=Source.fromFile("F://2.txt")
        val lines=file.getLines()
        for(content<- lines){
        println(content)
        }
    }catch{
    case ex:FileNotFoundException=>println("輸入的檔案不存在"+ex)
    case ex:Exception=> println(ex)
    }finally{
    println("通常用來釋放資源")
    }
}
}

2. Scala 中Array\Map等資料結構

2.1 定長陣列和可變陣列

預設情況下是定長陣列,若定義可變陣列,需要顯示匯入包

import scala.collection.mutable.ArrayBuffer

定義長度為2 的字串陣列

scala> val arrStr =Array("Scala","Spark")
arrStr: Array[String] = Array(Scala, Spark)

定義長度為3的整數型別陣列,初始值為0

scala> import scala.collection.mutable.ArrayBuffer
import scala.collection.mutable.ArrayBuffer

scala> val arrBufInt=ArrayBuffer[Int]()
arrBufInt: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer()

2.2 陣列常用演算法

scala> arrStr(0)="Storm" //直接賦值

scala> arrStr.mkString(",")//指定分隔符
res4: String = Storm,Spark

//將定長陣列變成變長陣列
scala> arrStr.toBuffer
res6: scala.collection.mutable.Buffer[String] = ArrayBuffer(Storm, Spark)

//陣列遍歷
scala> for(i<- 0 until arrStr.length)println(arrStr(i)) 
Storm
Spark
//或者 類似與java中的增強for
scala> for(elem<- arrStr)println(elem)
Storm
Spark

可變陣列特有操作

scala> arrBufInt+=1 //用+=在尾端新增元素
res10: arrBufInt.type = ArrayBuffer(1)

scala> arrBufInt+=(2,3,4,5) //同時新增多個元素
res11: arrBufInt.type = ArrayBuffer(1, 2, 3, 4, 5)

//用++= 可以直接追加一個集合

scala> arrBufInt++=arrBufInt //將自己追加給自己
res13: arrBufInt.type = ArrayBuffer(1, 2, 3, 4, 5, 1, 2, 3, 4, 5)

scala> arrBufInt++=Array(6,7,8)//追加個定長陣列
res14: arrBufInt.type = ArrayBuffer(1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 6, 7, 8)

//移除陣列的最後2個元素
scala> arrBufInt.trimEnd(2)
scala> arrBufInt
res16: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 6)

//移除陣列的第三個元素
scala> arrBufInt.remove(2)
res17: Int = 3

//在下標為2的位置開始移除4 個元素
scala> arrBufInt.remove(2,4)
scala> arrBufInt
res19: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 3, 4, 5, 6)

//將變長陣列轉換為定長陣列
scala> val arr=arrBufInt.toArray
arr: Array[Int] = Array(1, 2, 3, 4, 5, 6)

2.3 Map對映

預設情況下scala中使用不可變的對映,可變對映必須匯入scala.collection.mutable.Map

定義對映:

val mapCase=Map("china"->"beijing","france"->"paris")
scala>val bigData=Map("scala"->35,"hadoop"->30,"spark"->50)
bigData:Scala.collection.immutable.Map[String,Int]=Map(scala->35,hadoop ->30,spark->50)
//獲取key為scala的值
scala>bigData("scala")
res0:Int=35
scala>bigData.contains("hadoop") //判斷是否有key為hadoop的鍵值對
res1:Boolean=true
scala>bigData.getOrElse("spark",70) //若對映中存在包含key為spark的鍵值
//對,如果有就返回對應的值,否則返回70
res2:Int=50
//新增分隔符
scala>bigData.mkString("{",",","}")
res3:Strin{scala->35,hadoop->30,spark->50)
scala>bigData.drop(2) //以下標0開始,返回角標為2的元素
Map(spark->50)
res4:scala.collection.immutable.Map[String,Int]=Map(Spark->50)

構建可變對映

scala> import scala.collection.mutable.Map
import scala.collection.mutable.Map

scala> val bigDataVar=Map("scala"->35,"hadoop"->30,"spark"->50)
bigDataVar: scala.collection.mutable.Map[String,Int] = Map(spark -> 50, hadoop -> 30, scala -> 35)

scala> bigDataVar("spark")
res0: Int = 50

scala> bigDataVar("spark")=100//直接賦值

scala> bigDataVar("spark")
res2: Int = 100

scala> bigDataVar+=("kafka"->69) //在後面新增鍵值對
res3: bigDataVar.type = Map(spark -> 100, hadoop -> 30, scala -> 35, kafka -> 69)

scala> bigDataVar -=("kafka"->69) //刪除鍵值對,書上這個程式碼是錯的
<console>:14: error: type mismatch;
 found   : (String, Int)
 required: String
       bigDataVar -=("kafka"->69)
                            ^

scala> bigDataVar -=("kafka") //這麼寫就對了
res6: bigDataVar.type = Map(spark -> 100, hadoop -> 30, scala -> 35)

//遍歷對映
scala> for((k,v)<-bigDataVar)println(k+" "+v) 
spark 100
hadoop 30
scala 35
//只打印key
scala> for(k<-bigDataVar.keySet)println(k)
spark
hadoop
scala

2.4 Tuple元組

元組和陣列很像,但是它能包含不同種類型的資料


scala> val tuple1=(1,2,4,5,"hello")
tuple1: (Int, Int, Int, Int, String) = (1,2,4,5,hello)
scala> println(tuple1._1) //列印tuple中的元素
1

2.5 List 列表

和陣列很想,資料型別也都必須保持一致,但是區別如下

  • 列表中元素不可變
  • 列表表示一個連結串列
//定義一個列表
scala> val fruit:List[String]=List("apples","oranges","pears")
fruit: List[String] = List(apples, oranges, pears)

scala> val nums:List[Int]=List(1,2,4,4)
nums: List[Int] = List(1, 2, 4, 4)
//定義個空列表

scala> val empty:List[Nothing]=List()
empty: List[Nothing] = List()
//定義二維列表
scala> val dim:List[List[Int]]=
     | List(
     | List(1,2,3),
     | List(4,5,6),
     | List(7,8,9)
     | )
dim: List[List[Int]] = List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9))

定義列表的另一種方式
可以用一個無尾 Nil:: ,相當於c語言中的’null’和’->’

scala>val fruit="apples"::("oranges"::("pears"::Nil))
fruit:List[String]=List(apples,oranges,pears)
//定義一個空列表
scala>val empty=Nil
//定義二維列表
scala>val dim=(1::(2::(3::Nil)))::(4::(5::(6::Nil)))::(7::(8::(9::Nil)))::Nil
dim:List[List[Int]]=List(List(1,2,3),List(4,5,6),List(7,8,9))

列表基本操作

scala> class Test{
     | def ops{
     | val fruit= "apples"::("oranges"::("pears"::Nil))
     | val nums =Nil
     | println("Head of fruit "+fruit.head)//head是集合中的第一個元素
     | println("Tail of fruit "+fruit.tail) //tail是除了第一個元素外的所有元素的集合
     | println("Check if fruit is empty "+fruit.isEmpty)
     | println("Chek if nums  is empty "+nums.isEmpty)
     | }
     | }
defined class Test

scala> val t= new Test
t: Test = [email protected]51684c4e

scala> t.ops
Head of fruit apples
Tail of fruit List(oranges, pears)
Check if fruit is empty false
Chek if nums  is empty true

串聯列表
串聯列表有三種方法
1. 使用:::
2. 使用 List.:::()
3. 使用 List.concat(list1,list2)

//定義兩個list
scala> val fruit1="apples"::Nil
fruit1: List[String] = List(apples)

scala> val fruit2="orange"::Nil
fruit2: List[String] = List(orange)
//使用方法1
scala> var temp =fruit1:::fruit2
temp: List[String] = List(apples, orange)
//使用方法 2
scala> temp = fruit1.:::(fruit2)
temp: List[String] = List(orange, apples)
//使用方法3
scala> temp=List.concat(fruit1,fruit2)
temp: List[String] = List(apples, orange)

2.7 set集合

set集合同樣也有可變不可變 ,可變匯入scala.collection.mutable.Set
它的操作放發與list很像,直接上例子

scala> var s:Set[Int]=Set() //定義一個set
s: Set[Int] = Set()

scala> var s :Set[Int]=Set(1,3,4,5)
s: Set[Int] = Set(1, 3, 4, 5)

scala> var s =Set(1,3,4,5)
s: scala.collection.immutable.Set[Int] = Set(1, 3, 4, 5)
// 這裡展示基本操作

scala> val book=Set("scala","spark","hadoop")
book: scala.collection.immutable.Set[String] = Set(scala, spark, hadoop)

scala> println("Head of book " + book.head) //與List的head和tail一樣
Head of book scala

scala> println("tail of book "+book.tail)
tail of book Set(spark, hadoop)

scala> book.isEmpty
res2: Boolean = false

其它的集合方法大全的話,這裡就不列了,可以參考後文中的官方連結

2.7 scala官方文件連結

參考文獻

這裡參考書籍是《Spark零基礎實戰》,作者王家林和孔祥瑞.大部分程式碼都是敲過在本機上執行成功的.