scala是一種基于JVM的編程語(yǔ)言,spark框架是使用scala語(yǔ)言編寫的,要閱讀源碼就必須掌握scala,雖然spark可以采用java和python進(jìn)行開發(fā),但是最快速的支持方式任然是scala方式的API.
scala的特征
- java與scala可以實(shí)現(xiàn)混編,因?yàn)槠涠际腔贘VM的
- 類型推測(cè),scala可以不指定類型
- 特別接口trait(java中的interfaces與abstract結(jié)合)
- 模式匹配,match case(類似java switch case)
- 高階函數(shù)(函數(shù)的參數(shù)是函數(shù),函數(shù)的返回是函數(shù)),可進(jìn)行函數(shù)式編程
- 并發(fā)和分布式(Actor,類似Java多線程Thread)
scala特有類型
- Null :Trait,唯一實(shí)例null,是anyRef的子類
- Nothing :Trait,anyRef和anyVal的共同子類
- None :Option的兩個(gè)子類有some和None
- Unit :無(wú)返回值的函數(shù)類型,和void相對(duì)應(yīng)
- Nil :長(zhǎng)度為0 的list
- Any所有類型的超類,任何實(shí)例都屬于Any類型
- AnyRef所有引用類型的超類
- AnyVal所有值類型的超類
- Nothing所有其他類型的子類
變量的聲明
一般變量用var聲明,常量用val聲明,常量聲明后不能修改
- 可以指明變量類型(這種聲明的時(shí)候可以不用初始化)
var myVar : String = "Foo";
val myVal : String = "Foo";
- 也可以不指明(此時(shí)必須初始化,才能類型推斷)
var yourVar = "Foo";
val yourVal = "Foo";
- 多變量聲明
var xmax, ymax = 100;
- 聲明元組
var tuple = (40,"Foo")
- String類型
Scala本身沒(méi)有String類,其類型實(shí)際上是Java String,而Java的String對(duì)象的值是不可變的,與java一樣,要?jiǎng)?chuàng)建一個(gè)可修改的字符串,可以使用StringBuilder類。
val buf = new StringBuilder;
buf += 'a';
buf ++= "bcdef"; //都不會(huì)重新創(chuàng)建對(duì)象
println( "buf is : " + buf.toString );
- 數(shù)組類型
var z = Array("Runoob", "Baidu", "Google");
var z:Array[String] = new Array[String](3);
//多維數(shù)組
var myMatrix = ofDim[Int](3,3);
//合并數(shù)組
var myList1 = Array(1, 2, 3);
var myList2 = Array(4, 5, 6);
var myList3 = concat( myList1, myList2); //123456;concat函數(shù):import Array._;
//創(chuàng)建區(qū)間數(shù)組:使用range方法,返回一個(gè)數(shù)組Array
var yourList1 = range(10, 20, 2); //arg3是步長(zhǎng),默認(rèn)為1(不包含20)
- 集合
// 定義整型 List
//List的特征是其元素以線性方式存儲(chǔ),集合中可以存放重復(fù)對(duì)象。
val x = List(1,2,3,4)
// 定義 Set
//Set是最簡(jiǎn)單的一種集合。集合中的對(duì)象不按特定的方式排序,并且沒(méi)有重復(fù)對(duì)象。
var x = Set(1,3,5,7)
// 定義 Map
val x = Map("one" -> 1, "two" -> 2, "three" -> 3)
// 創(chuàng)建一個(gè)元組(這里包含兩個(gè)不同類型元素)
val x = (10, "Runoob")
// 定義 Option
//表示有可能包含值的容器,也可能不包含值
val x: Option[Int] = Some(5)
- 迭代器
迭代器不是一個(gè)容器,更確切的說(shuō)是逐一訪問(wèn)容器內(nèi)元素的方法。
var ita = Iterator(20,40,2,50,69, 90);
println("最小:" + ita.min);
println(itb.size + ":" + itb.length);
println(itb.size + ":" + itb.size);
while (it.hasNext){
println(it.next())
}
類與對(duì)象
- class成為伴生類,class中的屬性都是動(dòng)態(tài)的,scala中的class類默認(rèn)可以傳參數(shù),默認(rèn)的傳參數(shù)就是默認(rèn)的構(gòu)造函數(shù)。class 類屬性自帶getter ,setter方法。使用class時(shí)要new 。
- object: 修飾的稱為伴生對(duì)象;定義在object中的屬性(字段、方法)都是靜 態(tài)的,main函數(shù)寫在里面;scala 中的object是單例對(duì)象,可以看成是定義靜態(tài)的方法的類.object不可以傳參數(shù)。使用object時(shí),不用new.
//Point類文件
class Point(val xc: Int, val yc: Int) {
var x: Int = xc;
var y: Int = yc;
def move(dx: Int, dy: Int) {
x = x + dx;
y = y + dy;
println("x 的坐標(biāo)為:" + x);
println("y 的坐標(biāo)為:" + y);
}
}
//主函數(shù)
object Test {
def main(args: Array[String]) {
//創(chuàng)建一個(gè)Point對(duì)象
var pt = new Point(10, 20);
pt.move(10, 10);
}
}
①當(dāng)參數(shù)用==var==修飾那么可以通過(guò)對(duì)象修改其值;當(dāng)參數(shù)用==val==修飾那么無(wú)法通過(guò)對(duì)象來(lái)修改值;當(dāng)參數(shù)沒(méi)有修飾符,那么在外部無(wú)法通過(guò)對(duì)象來(lái)調(diào)用。
②若想增加一個(gè)類的傳入?yún)?shù),則需要在聲明的類中重寫this構(gòu)造函數(shù),這樣就可以在mian函數(shù)中聲明有增加的屬性的對(duì)象,當(dāng)然原來(lái)的對(duì)象也可以聲明。
重寫this函數(shù)
/*
* 重寫的構(gòu)造函數(shù),參數(shù)不能有修飾符
*/
def this (id:Int,name:String,facePower:Double ){
//首先要調(diào)用父構(gòu)造函數(shù)
this(id,name)
fcp = facePower
}
apply方法
使用此方法時(shí),可以在main函數(shù)中不通過(guò)new來(lái)創(chuàng)建一個(gè)對(duì)象,加載創(chuàng)建對(duì)象的這個(gè)類的時(shí)候,會(huì)自動(dòng)調(diào)用apply這個(gè)方法。
object ScalaDemo01 {
def main(args: Array[String]): Unit = {
val p = new Person("zs",19)
val person = Person("wagnwu",10) //不用使用new來(lái)創(chuàng)建一個(gè)實(shí)例
}
}
class Person(xname :String , xage :Int){
val name = "zs"
val age = xage
var gender = "m"
def this(name:String,age:Int,g:String){
this(name,age)
gender = g
}
}
object Person{
def apply(name:String,age:Int)={
new Person(name,age)
}
}
上面是使用apply方法的例子,類對(duì)象會(huì)自動(dòng)調(diào)用apply方法。
繼承
class SubClassName extends SuperClassName(){
/* Write your code
* methods and fields etc.
*/
}
override修飾可以繼承 父類final修飾的字段和方法
class Persion(val name: String){
override def toString = getClass.getName()+ "[name="+name+"]"
}
class SecretAgent (codename: String) extends Persion(codename){
override val name = "secret" //重寫 name
override val toString ="secret" //重寫 toString
}
val p = new SecretAgent("hello")
println(p.name)
println(p.toString)
注意:def只能重寫另一個(gè)def,val只能重寫另一個(gè)val或者是不帶參數(shù)的def,var只能重寫另一個(gè)抽象的var
循環(huán)控制
to包含最后一個(gè)數(shù),until不包含最后一個(gè)數(shù)
for(x <- 1 to 10)
for(x <- 1 until 10)
相當(dāng)于二重循環(huán)
for( a <- 1 to 3; b <- 1 to 3){
對(duì)集合的循環(huán)遍歷
for( var x <- List )
for循環(huán)當(dāng)作過(guò)濾器
for(a <- numList
if a % 2 == 0; if a < 5) {
println(a + "");
}
var retList = for{ a <- numList
if a % 2 == 0; if a < 5 } yield a;
方法函數(shù)
def functionName ([參數(shù)列表]) : [return type] = {
function body
return [expr]
}
如果方法沒(méi)有返回值,可以返回為 Unit,這個(gè)類似于 Java 的 void
**不寫明返回值的類型,程序會(huì)自行判斷,最后一行代碼的執(zhí)行結(jié)果為返回值
def addInt(a:Int,b:Int) = {
a + b
}
或者可以簡(jiǎn)寫為一行
def addInt(a:Int,b:Int) = x + y
省去def = {}
表示定義函數(shù)addInt,輸入?yún)?shù)有兩個(gè),分別為x,y,且均為Int類型,返回值為兩者的和,類型為Int。
val addInt = (x:Int,y:Int) =>x + y
遞歸模型
def fun2(num :Int) :Int= { //必須寫返回值類型
if(num ==1)
num
else
num * fun2(num-1)
}
print(fun2(5))
偏函數(shù)
def log(date :Date, s :String)= {
println("date is "+ date +",log is "+ s)
}
val date = new Date()
log(date ,"log1")
log(date ,"log2")
log(date ,"log3")
//想要調(diào)用log,以上變化的是第二個(gè)參數(shù),可以用偏應(yīng)用函數(shù)處理
val logWithDate = log(date,_:String) //下劃線相當(dāng)于占位符的作用,手動(dòng)傳入即可
logWithDate("log11")
高階函數(shù)
高階函數(shù):函數(shù)的參數(shù)是函數(shù),或者函數(shù)的返回類型是函數(shù),或者函數(shù)的參數(shù)和函數(shù)的返回類型是函數(shù)的函數(shù)。
//函數(shù)的參數(shù)是函數(shù)
def hightFun(f : (Int,Int) =>Int, a:Int ) : Int = {
f(a,100)
}
def f(v1 :Int,v2: Int):Int = {
v1+v2
}
println(hightFun(f, 1))
//函數(shù)的返回是函數(shù)
//1,2,3,4相加
def hightFun2(a : Int,b:Int) : (Int,Int)=>Int = {
def f2 (v1: Int,v2:Int) :Int = {
v1+v2+a+b
}
f2
}
println(hightFun2(1,2)(3,4))
//函數(shù)的參數(shù)是函數(shù),函數(shù)的返回是函數(shù)
def hightFun3(f : (Int ,Int) => Int) : (Int,Int) => Int = {
f
}
println(hightFun3(f)(100,200))
println(hightFun3((a,b) =>{a+b})(200,200))
//以上這句話還可以寫成這樣
//如果函數(shù)的參數(shù)在方法體中只使用了一次 那么可以寫成_表示
println(hightFun3(_+_)(200,200))
Trait特性
Trait的概念理解
1》 Scala Trait(特征) 相當(dāng)于 Java 的接口,實(shí)際上它比接口還功能強(qiáng)大。
2》與接口不同的是,它還可以定義屬性和方法的實(shí)現(xiàn)。抽象類和接口的結(jié)合。
3》一般情況下Scala的類可以繼承多個(gè)Trait,從結(jié)果來(lái)看就是實(shí)現(xiàn)了多重繼承。Trait的繼承用exten關(guān)鍵字繼承,多繼承時(shí)多個(gè)Trait之間用with連接。
4》Trait(特征) 定義的方式與類類似,但它使用的關(guān)鍵字是 trait。
5》繼承的多個(gè)trait中如果有同名的方法和屬性,必須要在類中使用“override”重新定義。
6》trait中不可以傳參數(shù)
trait Read {
val readType = "Read"
val gender = "m"
def read(name:String){
println(name+" is reading")
}
}
trait Listen {
val listenType = "Listen"
val gender = "m"
def listen(name:String){
println(name + " is listenning")
}
}
class Person() extends Read with Listen{
override val gender = "f"
}
object test {
def main(args: Array[String]): Unit = {
val person = new Person()
person.read("zhangsan")
person.listen("lisi")
println(person.listenType)
println(person.readType)
println(person.gender)
}
}
模式匹配
Java中的模式匹配為 switch case ;
Scala 提供了強(qiáng)大的模式匹配機(jī)制,應(yīng)用也非常廣泛,除了匹配值還可以匹配類型,類型的匹配必須要有變量名。
一個(gè)模式匹配包含了一系列備選項(xiàng),每個(gè)都開始于關(guān)鍵字 case。
每個(gè)備選項(xiàng)都包含了一個(gè)模式及一到多個(gè)表達(dá)式。箭頭符號(hào) => 隔開了模式和表達(dá)式。
object Lesson_Match {
def main(args: Array[String]): Unit = {
val tuple = Tuple6(1,2,3f,4,"abc",55d)
val tupleIterator = tuple.productIterator
while(tupleIterator.hasNext){
matchTest(tupleIterator.next())
}
}
/**
* 注意點(diǎn):
* 1.模式匹配不僅可以匹配值,還可以匹配類型
* 2.模式匹配中,從上到下順序匹配,如果匹配到對(duì)應(yīng)的類型或值,就不再繼續(xù)往下匹配
* 3.模式匹配中,都匹配不上時(shí),會(huì)匹配到 case _ ,相當(dāng)于default
* 4. 模式匹配的時(shí)候,模式范圍小的在最前面
*/
def matchTest(x:Any) ={
x match {
case x:Int=> println("type is Int") //類型匹配,必須要有變量名
case 1 => println("result is 1")
case 2 => println("result is 2")
case 3=> println("result is 3")
case 4 => println("result is 4")
case x:String => println("type is String")
// case x :Double => println("type is Double")
case _ => println("no match")
}
}
}