学习Spark就要学习Scala,今天开始快速学习Scala.直接在这里做笔记了.
文章目录
1 Scala基础与语法
1.1 基本数据类型
8中常见数据类型:Byte
,Char
,Short
,Int
,Long
,Float
,Double
和Boolean
. 这里的Float
和 Double
的具体区别就是 :
浮点数如0.0f或者0.0F,若没有 f 后缀则是Double变量
String
也是基本数据类型,它属于java.lang
包,这个包是默认导入的.
1.2 Scala变量声明
Scala通过
var
和val
来声明变量.其中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
注意的是,在
for
和while
中都没有用到break
和continue
,这是因为在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 = Test@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
串联列表
串联列表有三种方法
- 使用
:::
- 使用
List.:::()
- 使用
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零基础实战》,作者王家林和孔祥瑞.大部分代码都是敲过在本机上运行成功的.