前言java
Scala是以JVM爲運行環境的面向對象的函數式編程語言,它能夠直接訪問Java類庫而且與Java框架進行交互操做。正如以前所介紹,Spark是用Scala語言編寫的,Kafka server端也是,那麼深刻學習Scala對掌握Spark、Kafka是必備掌握技能。編程
本篇文章主要介紹,在學習、編寫Spark程序時,至少要掌握的Scala語法,多以示例說明。建議在用Scala編寫相關功能實現時,邊學習、邊應用、邊摸索以加深對Scala的理解和應用。數組
1. 變量、表達式、循環、Option、方法和函數安全
1.1 聲明變量數據結構
def main(args: Array[String]): Unit = { //使用val定義的變量值是不可變的,至關於java裏用final修飾的變量 val i = 1 //使用var定義的變量是可變的,在Scala中鼓勵使用val var s = "hello" //Scala編譯器會自動推斷變量的類型,必要的時候能夠指定類型 //變量名在前,類型在後 val str: String = "hello" }
1.2 表達式app
1.2.1 條件表達式框架
def main(args: Array[String]): Unit = { val x = 1 // 判斷x是否大於0,將最終結果賦給y,打印y // 兩者等效, Scala語言強調代碼簡潔 // var y = if(x > 0) {x} else {-1} // val y = if(x > 0) x else -1 // 支持混合類型表達式,返回值類型是Any // var y = if(x > 0) x else "no" // 若是缺失else,至關於if (x > 0) 1 else () // scala表達式中有一個Unit類,寫做(),至關於java中void // val y = if(x > 0) 1 // if和else if val f = if (x < 0) 0 else if (x >= 1) 1 else -1 println(y) }
1.2.2 塊表達式編程語言
def main(args: Array[String]): Unit = { val x = 0 // scala中{}可包含一系列表達式,塊中運行最終結果爲塊的值 val result = { if(x < 0) -1 else if(x >= 1) 1 else "error" } println(result) }
1.3 循環
函數式編程
Scala裏面while循環和Java中的while循環使用方式相似,這裏主要以for循環爲例:函數
def main(args: Array[String]): Unit = { // 表達式1 to 10返回一個Range區間,每次循環將區間中的一個值賦給i for (i <- 1 to 3) { println(i) } //i表明數組中的每一個元素 val arr = Array("a", 1, "c") for (i <- arr) { println(i) } //高級for循環 //每一個生成器均可以帶一個條件,注意:if前面沒有分號 //至關於雙層for循環,i每得到一個值對1to3進行所有遍歷並賦值給j而後進行條件判斷 for (i <- 1 to 3; j <- 1 to 3 if (i != j)) { println(i + j) } //for推導式:若是for的循環體以yield開頭,則該循環會構建一個集合 // 每次迭代生成集合中的一個元素 集合類型爲Vector var v = for (i <- 1 to 3) yield i * i println(v) //遍歷一個數組,to:包頭包尾;until:包頭不包尾 for (i <- arr.length - 1) { println(arr(i)) } for(i <- 0 until arr.length) { println(arr(i)) } }
1.4 Option類型
在Scala中Option類型樣例類用來表示可能存在或也可能不存在的值(Option的子類有Some和None)。Some包裝了某個值,None表示沒有值:
def main(args: Array[String]): Unit = { val map = Map("a"->1,"b"->2) //根據key獲取value匹配match中的邏輯有值返回Some類型(已封裝數據),無值返回None val v = map.get("b") match { case Some(i) => i case None => 0 } println(v) //更好的方式 val value = map.getOrElse("c",0) println(value) }
1.5 方法和函數
Scala中的+、-、*、/、%等操做符的做用與Java同樣,位操做符&、|、^、>>、<<也同樣。但在Scala中:這些操做符其實是方法。例如:a + b是a.+(b)方法調用的簡寫:a 方法 b能夠寫成 a.方法(b)。
方法的返回值類型能夠不寫,編譯器能夠自動推斷出來,可是對於遞歸函數,必須指定返回類型。
def str = "a" 成立,定義一個字符串
在函數式編程語言中,函數能夠像任何其餘數據類型同樣被傳遞和操做:
偏函數:
//偏函數,它是PartialFunction[-A,+B]的一個實例,A表明參數類型,B表明返回值類型,經常使用做模式匹配(後文闡述)。
def func1: PartialFunction[String, Int] = { case "one" => 1 case "two" => 2 case _ => -1 } def func2(num: String): Int = num match { case "one" => 1 case "two" => 2 case _ => -1 } def main(args: Array[String]) { println(func1("one")) println(func2("three")) }
2. 數組、映射、元組、集合
2.1 數組
import scala.collection.mutable.ArrayBuffer //scala導包好比導入scala.collection.mutable下全部的類:scala.collection.mutable._ object ArrayDemo { def main(args: Array[String]): Unit = { println("======定長數組======") // 初始化一個長度爲8的定長數組,全部元素初始化值爲0 var arr1 = new Array[Int](8) // 底層調用的apply方法 var arr2 = Array[Int](8) //toBuffer會將數組轉換成數組緩衝 println(arr1.toBuffer) // ArrayBuffer(0, 0, 0, 0, 0, 0, 0, 0) println(arr1(2)) // 使用()來訪問元素 println("=======變長數組(數組緩衝)======") val varr = ArrayBuffer[Int]() //向數組緩衝尾部追加一個或多個元素(+=) varr += 1 varr += (2, 3) //追加一個數組用 ++= varr ++= Array(4, 5) varr ++= ArrayBuffer(6, 7) //指定位置插入元素-1和3;參數1:指定位置索引,參數2:插入的元素能夠是多個 // def insert(n: Int, elems: A*) { insertAll(n, elems) } varr.insert(0,-1,3) varr.remove(0) //刪除指定索引處的元素 //從指定索引處開始刪除,刪除多個元素;參1:指定索引,參2:刪除個數 varr.remove(0,2) // 從0索引開始刪除n個元素 // varr.trimStart(2) //從最後一個元素開始刪除,刪除指定個數的元素(length-n max 0) varr.trimEnd(2) ) //reduce ==>非並行化集合調用reduceLeft //(((1+8)+3)+5)... println(varr.reduce((x,y)=> x+y)) println(varr.reduce(_+_)) println(varr.reduce(_-_)) Array("one","two","three").max //two,字符串比較大小,按照字母表順序 Array("one","two","three").mkString("-")//以"-"做爲數組中元素間的分隔符one-two-three Array("one","two","three").mkString("1","-","2")//1one-two-three2 //參1:arr元素的數組個數,參2:arr中每一個數組中元素個數 val arr = Array.ofDim[Int](2, 3) arr.head arr.last //數組的第一個和最後一個元素 } }
yield關鍵字將原始的數組進行轉換會產生一個新的數組,原始的數組不變
def main(args: Array[String]) { //定義一個數組 val arr = Array(1, 2, 3, 4, 5, 6, 7, 8, 9) //將偶數取出乘以10後再生成一個新的數組 val res = for (e <- arr if e % 2 == 0) yield e * 10 println(res.toBuffer) //filter過濾接收一個返回值爲boolean的函數,過濾掉返回值爲false的元素 //map將數組中的每個元素取出來(_)進行相應操做 val r = arr.filter(_ % 2 == 0).map(_ * 10) println(r.toBuffer) //數組元素求和,最大值,排序 println(arr.sum+":"+arr.max+":"+arr.sorted.toBuffer) }
2.2 映射
在Scala中,把哈希表這種數據結構叫作映射,相似於Java中的Map。
在Scala中,有兩種Map:
不可變Map:scala.collection.immutable.Map(能夠存儲一些配置或參數供多個線程訪問,保證線程安全,具體還要結合業務實際場景),內容不更改
可變Map:scala.collection.mutable.Map==>相似於Java中的HashMap,能夠進行put、get、remove等操做,內容可變
map += ("c" -> 3) map += (("d",4)) 增長元素 -=移除元素 +/-增長或移除一個元素並返回一個新的集合
注意:一般咱們在建立一個集合時會用val這個關鍵字修飾一個變量,那麼就意味着該變量的引用不可變,該引用中的內容是否是可變還取決於這個引用指向的集合的類型
2.3 元組
映射是K/V對偶的集合,對偶是元組的最簡單形式,元組能夠裝着多個不一樣類型的值,元組是不可變的
zip命令能夠將多個值綁定在一塊兒(將兩個數組/集合的元素一一對偶):
注意:若是兩個數組的元素個數不一致,拉鍊操做後生成的數組的長度爲較小的那個數組的元素個數
對於元組val t = (1, 3.14, "Fred"),val (first, second, _) = t // second等於3.14
2.4 集合
Scala的集合有三大類:序列Seq、集Set、映射Map,全部的集合都擴展自Iterable特質。集合分可變(mutable)和不可變(immutable)兩種類型,immutable類型的集合初始化後長度和內容都不能改變(注意與val修飾的變量進行區別)
2.4.1 Seq/List
在Scala中列表要麼爲空(Nil表示空列表)要麼是一個head元素加上一個tail列表。
9 :: List(5, 2) :: 操做符是將給定的頭和尾建立一個新的列表【注意::: 操做符是右結合的,如9 :: 5 :: 2 :: Nil至關於 9 :: (5 :: (2 :: Nil))】
def main(args: Array[String]): Unit = { //建立一個不可變集合 val lt = List(1, 2, 3) /*//添加元素到lt前面生成一個新的List val lt2 = ("a", -1, 0) :: lt val lt3 = lt.::(0) val lt4 = 0 +: lt val lt5 = lt.+:(0) println(lt + "==>" + lt2 + "==" + lt3 + "==" + lt4 + "==" + lt5) val lt6 = lt :+ 4 println("添加元素到後面:"+lt6 )*/ //合併兩個集合,lt0在lt前面 val lt0 = List(4,5,6,7) val lt7 = lt0.union(lt) val lt8 = lt0 ++ lt println(lt7 +":"+lt8 ) println("lt0在lt後面"+lt ++ lt0) //將兩個集合中的元素一一綁定,若是元素數不一致以較少元素集合爲準 println(lt0.zip(lt).toMap) //將lt0插入到lt前面生成一個新的集合 println(lt0 ++: lt) println(lt.:::(lt0)) } def main(args: Array[String]): Unit = { // 構建一個可變列表,初始有3個元素1,2,3 alt+enter導包 val lst0 = ListBuffer[Int](1,2,3) //建立一個空的可變列表 val lst1 = new ListBuffer[Int] //向lst1中追加元素,注意:沒有生成新的集合 lst1 += 4 lst1.append(5) println(lst1) //將lst1中的元素最近到lst0中, 注意:沒有生成新的集合 println(lst0 ++= lst1) //將lst0和lst1合併成一個新的ListBuffer 注意:生成了一個集合 println(lst0 ++ lst1) //將元素追加到lst0的後面生成一個新的ListBuffer val lst3 = lst0 :+ 5 println(lst3) } def main(args: Array[String]): Unit = { // 構建一個可變列表,初始有3個元素1,2,3 alt+enter導包 val lst0 = ListBuffer[Int](1,2,3) //建立一個空的可變列表 val lst1 = new ListBuffer[Int] //向lst1中追加元素,注意:沒有生成新的集合 lst1 += 4 lst1.append(5) println(lst1) //將lst1中的元素最近到lst0中, 注意:沒有生成新的集合 println(lst0 ++= lst1) //將lst0和lst1合併成一個新的ListBuffer 注意:生成了一個集合 println(lst0 ++ lst1) //將元素追加到lst0的後面生成一個新的ListBuffer val lst3 = lst0 :+ 5 println(lst3) } def main(args: Array[String]): Unit = { /* //建立一個List val lst0 = List(1,7,9,8,0,3,5,4,6,2) //將lst0中每一個元素乘以10後生成一個新的集合 val lst1 = lst0.map(_*10) val lst2 = for(i <- lst0) yield i * 10 println(lst1 + ":" +lst2) //將lst0中的偶數取出來生成一個新的集合 val lst3 = lst0.filter(_ % 2 == 0) val lst4 = for(i <- lst0 if(i % 2 == 0)) yield i println(lst3 + ":" +lst4) //將lst0排序後生成一個新的集合 val lst5 = lst0.sorted//升序 val lst6 = lst0.sortWith(_>_)//降序 val lst7 = lst0.sortBy(x => x)//升序 println(lst5 + ":" +lst6 + ":" +lst7) //反轉順序 println(lst5.reverse) //將lst0中的元素4個一組,類型爲Iterator[List[Int]] val it = lst0.grouped(4) // println(it.toBuffer) //將Iterator轉換成List val lst8 = it.toList //將多個list壓扁成一個List println(lst8.flatten) //先按空格切分,再壓平 val lines = List("hello tom hello jerry", "hello jerry", "hello kitty") lines.map(_.split(" ")).flatten lines.flatMap(_.split(" "))// //並行計算求和 println(lst0.par.sum) println(lst0.par.reduce(_+_))//非指定順序 println(lst0.par.reduceLeft(_+_))//指定順序 //摺疊:有初始值(無特定順序) val lst11 = lst0.fold(100)((x, y) => x + y) //摺疊:有初始值(有特定順序) val lst12 = lst0.foldLeft(100)((x, y) => x + y) */ //聚合 val arr = List(List(1, 2, 3), List(3, 4, 5), List(2), List(0)) // println(arr.flatten.sum) /*先局部求和,再彙總 _+_.sum:第一個下劃線是初始值和後面list.sum和,_.sum是list的和,非並行化時只初始化1次只攜帶1次 _+_:初始值和list元素和的和 */ val result = arr.aggregate(10)(_+_.sum,_+_) val res = arr.aggregate(10)((x,y)=>x+y.sum,(a,b)=>a+b) println(result+":"+res) val l1 = List(5,6,4,7) val l2 = List(1,2,3,4) //求並集 val r1 = l1.union(l2) //求交集 val r2 = l1.intersect(l2) //求差集 val r3 = l1.diff(l2) println(r3) }
2.4.2 Set
def main(args: Array[String]): Unit = { //不可變Set /* val set1 = new HashSet[Int]() //將元素和set1合併生成一個新的set,原有set不變 val set2 = set1 + 4 //set中元素不能重複 val set3 = set1 ++ Set(5, 6, 7) val set0 = Set(1,3,5) ++ set3 println(set0)*/ //建立一個可變的HashSet val set1 = new mutable.HashSet[Int]() //向HashSet中添加元素 set1 += 2 //add等價於+= set1.add(4) set1 ++= Set(1,3,5) println(set1) //刪除一個元素 set1 -= 5 set1.remove(2) println(set1) }
推薦文章: