基礎語法
- 區分大小寫 - Scala是區分大小寫的,比如標識符
Hello
和hello
在Scala中表示不同的含義(對象)。 - 類名稱 - 對於所有類名,第一個字母應爲大寫。如果使用多個單詞來形成類的名稱,則每個內部單詞的第一個字母應該是大寫。
示例 -class MyFirstScalaClass
,class Employee
*類等。 - 方法名稱 - 所有方法名稱應以小寫字母開頭。如果使用多個單詞形成方法的名稱,則每個內部單詞的第一個字母應爲大寫。
示例 -def myMethodName()
,def getName()
等。 - 程序文件名 - 程序文件的名稱應與對象名稱完全匹配。保存文件時,您應該使用對象名稱保存它(記住Scala是區分大小寫的),並將
.scala
附加到文件名稱的末尾。 (如果文件名和對象名不匹配,則程序將不會編譯)。
示例 - 假設HelloWorld
是對象名稱。 那麼文件應該保存爲HelloWorld.scala
。 - def main(args:Array [String]) - Scala程序從
main()
方法開始,這是每個Scala程序的強制性部分。
變量
-
var 用來聲明變量,爲可變變量。
var myVar : String = "Foo"
-
val 用來聲明不可變變量,不能對其進行修改。
val myVal : String = "Foo"
變量的類型在變量名稱和等號之前指定。可以通過其數據類型來定義任何類型的Scala變量。如下:
var or val VariableName : DataType = [Initial Value]
eg:val myVal:String = “datatype” //定義一個String類型的不可變變量,值爲datatype
不分配初始值,則語法爲:
```scala
var myVar :Int;
val myVal : String;
控制結構
-
for循環,格式如下:
for(變量<-表達式) 語句塊 其中變量<-表達式被稱爲生成器 for(i <- 1 to 5) println(i) 輸出:1 2 3 4 5
①可以設置步長,i <- 1 to 5 by 2,設置的步長爲2,及只取1 3 5。
②還可以設置過濾條件,稱爲守衛的表達式,比如只輸出1到5之間的所有偶數,可以使用以下語句進行過濾:
for(i <- 1 to 5 if i%2==0) println(i)
③for推導式,可以將每次執行時創造的值的集合返回,集合的類型由生成器中的集合類型確定。通過for循環遍歷一個或多個集合,對集合中的元素進行推導,從而計算得到新的集合,用於後續的其他處理。
for(變量<-表達式) yield {語句塊}
數據結構
-
Scala有一套豐富的容器(Collection)庫,包括列表(List)、數組(Array)、集合(Set)、映射(Map)。
三個包來組織容器類,
scala.collection
、scala.collection.mutable
、scala.collection.immutable
。mutable是可變的集合、immutable是不可變的集合。-
列表(List)
scala的List一旦被定義,其值就不能改變,因此聲明List是必須初始化,屬於immutable包中。
//可以使用操作符::,在已有列表前端增加元素。 val oherList = "hcx"::strList
執行完上述語句,將產生一個新的List用於存放新的List,原來的strList保持不變。空列表爲Nil。
-
集合(Set)
包括可變集和不可變集,分別在兩個包中,缺省情況下創建的是immutable包中的不可變集合,如果要聲明一個可變集,則需要提前引入
scala.collection.mutable.Set
。 -
映射(Map)
和集合(Set)相似。如果想使用可變映射,需要導入相應的包。不可變映射不能更新、增加映射中元素,如果要更新元素,則需要定義可變的映射,可以使用+=操作來添加新的元素。報錯如下圖所示。
val university = Map("x" -> "value1","y" -> "value2","z" -> "value3") //取值 university("x") //循環遍歷映射 for((k,v)<-映射) 語句塊
[外鏈圖片轉存失敗(img-YIig0iwD-1569465571641)(photo/1568025463950.png)]
-
-
迭代器(Iterator)
- 迭代器包含兩個基本操作,next和hasNext。next可以返回迭代器的下一個元素,hasNext用於檢測是否還有下一個元素。
- grouped和sliding兩個方法返回迭代器。grouped方法返回元素的增量分塊,sliding方法返回一個元素的滑塊分塊。
-
數組(Array)
定長數組Array
val intValueArr = new Array[Int](3) intValueArr(0) = 12 intValueArr(1) = 24 intValueArr(2) = 48 val myStrArr = new Array[String](3) myStrArr(0) = "value1" myStrArr(1) = "value2" myStrArr(2) = "value3" //二維數組和三維數組 val myMatrix = Array.ofDim[Int](3,4) 類型實際是Array[Array[Int]] //訪問元素 myMatrix(0)(1)
變長數組需要導入包,ArrayBuffer
import scala.collection.mutable.ArrayBuffer val aMutableArr = ArrayBuffer(10,20,30) aMutableArr += 40 aMutableArr.insert(2,60,40) aMutableArr -= 40 var temp = aMutableArr.remove(2)
-
元祖(Tuple)是不同類型的值的聚集。元組和列表不同,列表中各個元素必須是相同類型,而元祖可以包含不同類型的元素。
使用
_
來訪問元祖中元素。val tuple = ("value1",10,521.1) println(tuple._1) println(tuple._2)
[外鏈圖片轉存失敗(img-TNh6WQFD-1569465571643)(photo/1568164025539.png)]
類
class Xxx{ //定義類的字段和方法 }
- 當類沒有參數傳遞時,可以通過new Xxx 來生成對象,當需要傳遞對象時,需要在 new Xxx()括號中輸入需要傳遞的參數。另外,新建對象後,調用其中的方法時,如果是無參方法,可以省力方法名後面的圓括號。
- scala中沒有提供getter和setter方法,當成員設置爲私有屬性時,可以通過定義方法來對這個私有成員進行訪問和修改。
-
輔助構造器
scala構造器包含一個主構造器和若干個輔助構造器。
輔助構造器的名稱爲this,每個輔助構造器都必須調用一個此前已經定義的輔助構造器或者主構造器。
class Counter{ private var value = 0 private var name = "" private var mode = 1 def this(name:String){ //第一個輔助構造器 this() //調用主構造器 this.name = name } def this(name : String, mode : Int){ //第二個輔助構造器 this(name) //調用前一個輔助構造器 this.mdoe = mode } def increment(step: Int):Unit = {value += step} def current():Int = {value} def info():Unit = {printf("Name:%s and mode is %d\n",name,mode)} } object MyCounter{ def main(args:Array[String]){ val myCounter1 = new Counter val myCounter2 = new Counter("Runner") val myCounter3 = new Counter("Timer",2) myCounter1.info myCounter1.increment(1) printf("Current Value is : %d\n",myCounter1.current) } }
-
單例對象和伴生對象
使用object關鍵字實現單例對象,具備和Java靜態方法同樣的功能。
object Person{ private var lastId = 0 def newPersonId() = { lastId += 1 lastId } }
在Java中,經常需要用到同時包含實例方法和靜態方法的類,在Scala中可以通過伴生對象來實現。
當單例對象與某個類具有相同的名稱時,它被稱爲這個類的伴生對象。
注意:類和它的伴生對象必須存在於同一個文件中,而且可以相互訪問私有成員(字段和方法)
-
apply方法和update方法
在scala中,apply方法和update方法都會遵循相關的約定被調用,約定如下:
- 用括號傳遞給變量(對象)一個或多個參數時,scala會把它轉換成對apply方法的調用
- 當對帶有括號幷包括一到若干參數的對象就那些賦值時,編譯器將調用對象的update方法,在調用時,是把括號裏的參數和等號右邊的對象一起作爲update方法的輸入參數來執行調用。
class TestApply{ } class ApplyTest{ def apply() = println("apply mehod in class is called!") def greetingOfClass : Unit = { println("Greeting!") } } object ApplyTest{ def apply() = { println("apply method in object is called") new ApplyTest() } } object TestApply{ def main(args:Array[String]){ val a = ApplyTest() //調用伴生對象中的apply方法 a.greetingOfClass a() //這裏調用伴生類中的apply方法 } }
執行結果:
apply method in object is called Greeting! apply mehod in class is called!
update方法類似,比如:
val mystrArr = new Array[String](3) mystrArr(0) = "BigData" mystrArr(1) = "Hadoop" mystrArr(2) = "Spark"
上述採用圓括號的形式,mystrArr(0)是因爲存在update方法的機制。
繼承
scala中的繼承與Java有着顯著的不同:
- 重寫一個非抽象方法必須使用override修飾符。
- 只有主構造器可以調用超類的主構造器。
- 在子類中重寫超類的抽象方法時,不需要使用override關鍵字。
- 可以重寫超類中的字段。
下面構造一個抽象類:
定義注意:
- 定義一個抽象類,需要使用關鍵字abstract
- 定義一個抽象類的抽象方法,不需要關鍵字abstract,只要把方法體空着
- 抽象類中定義的字段,只要沒有給出初始化值,就表示一個抽象字段,但是,抽象字段必須要聲明類型。
abstract class Car{ //抽象類,不能直接被實例化
val carBrand:String //字段沒有初始化值,就是一個抽象字段
def info() //抽象方法,不需要使用abstract關鍵字
def greeting() {println("my Car!")}
}
擴展類繼承Car類
class BMWCar extends Car{
override val carBrand = "BMW"
def info() {printf("this is a %s car.",carBrand)}
overrride def greeting() {println("my BMW car!")} //重寫超類非抽象方法,必須使用override關鍵字
}
特質(trait)
scala中的特質相當於Java中的接口,特質定義使用關鍵字trait,定義好特質後,就可以使用extends或with關鍵字把特質混入類中。
trait CarId{
var id : Int
def currentId:Int
}
trait CarGreeting{
def greeting(msg : String){println(msg)}
}
class BMWCarId extends CarId with CarGreeting{
override var id = 10000
def currentId() :Int = {id +1;id}
}
object MyCar{
def main(args:Array[String]){
val myCarId1 = new BMWCarId()
myCarId1.greeting("my first Car")
printf("My first CarId is %d\n",myCarId1.currentId)
}
}
模式匹配
最常用於match語句中。
val colorNum = 1
val colorStr = colorNum match{
case 1 => "red"
case 2 => "green"
case _ => "not Allowed"
}
println(colorStr)
//使用變量
val colorNum = 4
val colorStr = colorNum match{
case 1 => "red"
case 2 => "green"
case unexpected => unexpected + "is not Allowed"
}
println(colorStr)
case類是一種特殊的類,經過優化以被用於模式匹配。
case class Car(brand : String,price : Int)
val Car1 = new Car("BYD",89000)
val Car2 = new Car("BMW",120000)
val Car3 = new Car("benz",150000)
for(car <- List(Car1,Car2,Car3)){
car match{
case Car("BYD",89000) => println("Car1")
case Car("BMW",120000) => println("Car2")
case Car("benz",150000) => println("Car3")
}
}
函數定義
[外鏈圖片轉存失敗(img-Vii1BCfr-1569465571643)(photo/1568172061848.png)]
-
匿名函數(Lamda表達式)
(num : Int) => num * 2 (參數) => 表達式 // 如果參數只有一個,參數的圓括號可以省略 val myNumFunc: Int => Int = (num:Int) => num * 2 // scala具有類型推斷機制,可以將表達式改爲下列 val myNumFunc = (num:Int) => num * 2
-
閉包(反映了一個從開放到封閉的過程)
var more = 1 val addMore = (x:Int) => x + more addMore(10) //輸出結果爲11
每個閉包都會訪問閉包活躍的元素。
-
佔位符語法
val numList = List(-3,-1,0,1,3,9) numList.filter(x => x>0) numList.filter(_ > 0) //可以使用_來作爲一個或多個參數的佔位符
集合操作
-
遍歷操作
映射(Map)、列表(List)的遍歷,可以使用for循環進行遍歷,也可以使用foreach進行遍歷。
-
map和flatMap操作
- map操作是針對集合的典型變換操作,它將某個函數應用到集合中的每個元素,併產生一個結果集合。
val books = List("Hadoop","Hive","hdfs") book.map(s => s.toUpperCase) List(HADOOP,HIVE,HDFS)
2. flatMap會傳入一個函數,該函數對每個輸入都會返回一個集合(而不是一個元素),然後,flatMap把生成的多個集合拍扁稱爲一個集合。
val books = List("Hadoop","Hive","hdfs") book flatMap(s => s.toList) List[Char] = List(H,a,o,o,p,H,i,v,e,h,d,f,s)
上面的flatMap執行時,會把books中的每個元素都調用toList,生成List[Char],最終,多個Char的集合被拍扁成一個集合。
-
filter操作
遍歷一個集合並從中獲取滿足指定條件的元素組成一個新的集合,scala中可以通過filter操作來實現。
val university = Map("key1" -> "value1","key2" -> "value2","hcx" -> "hcx3") val universityOfHcx = university filter {kv => kv._2 contains "hcx"} val universityOfH = university filter {kv => kv._2 startsWith "h"}
-
reduce操作
使用reduce這種二元操作對集合中的元素進行歸納,reduce包含reduceLeft和reduceRight兩種操作,前者從集合的頭部開始操作,後者從集合的尾部開始操作。
val list = List(1,2,3,4,5) list.reduceLeft(_ + _) 15 list.reduceRight(_ + _) 15
-
fold操作
fold摺疊操作和reduce操作類似,fold操作需要從一個初始的值開始,並以該值作爲上下文,處理集合中的每個元素。
val list = List(1,2,3,4,5) list.fold(10)(_ * _) 1200
WordCount實例
import java.io.File import scala.io.Source object WordCount{ def main(args: Array[String]) : Unit = { val dirfile = new File("D:\\wordcount") val files = dirfile.listFiles for(file <- files) println(file) val listFiles = files.toList val wordsMap = scala.collection.mutable.Map[String,Int]() listFiles.foreach(file => Source.fromFile(file).getLines().foreach(line => line.split(" ").foreach( word =>{ if(wordsMap.contains(word){ wordsMap(word) += 1 }else{ wordsMap += (word -> 1) } ) }))) println(wordsMap) for((k,v) <- wordsMap) println(k + ":" + v) } }