Scala基础
Scala是一门类似Java的多范式语言,集合了面向对象编程和函数式编程的特性。
使用Scala语言编写Spark应用程序的考虑:
1)Scala具有强大的并发性,支持函数式编程,可以更好的支持分布式系统。在大数据时代,为了提高应用程序的并发性,函数式编程日益收到关注;
2)Scala兼容Java,可以与Java互操作。Scala代码文件会被编译成Java的class文件,开发者可以从Scala中调用Java类库;
3)Scala代码简洁优雅;
4)Scala支持高效的交互式编程。其提供了交互式解释器(Read-Eval-Print Loop, REPL),因此在Spark-shell中可进行交互式编程。
5)Scala是Spark的开发语言。用Scala语言编写Spark应用程序可以获得最好的执行性能。
基本数据类型
1、Scala的数据类型包括:Byte、Char、Short、Int、Long、Float、Double和Boolean(注意首字母大写)
2、和Java不同的是,在Scala中,这些类型都是"类",并且都是包scala的成员,比如,Int的全名是scala.Int。对于字符串Scala用java.lang.String类来表示字符串
除了以上9种基本类型,Scala还提供了一个Unit类型,类似Java中的void类型。
字面量
val i=123//123就是整数字面量
val i=3.14//3.14就是浮点数字面量
val i=true//true就是布尔型字面量
val i='A'//'A'就是字符字面量
val i="Hello"//"Hello"就是字符串字面量
基本操作
• 算术运算符:加(+)、减(-) 、乘(*) 、除(/) 、余数(%);
• 关系运算符:大于(>)、小于(<)、等于(==)、不等于(!=)、大于等于(>=)、小于等于(<=)
• 逻辑运算符:逻辑与(&&)、逻辑或(||)、逻辑非(!);
• 位运算符:按位与(&)、按位或(|)、按位异或(^)、按位取反(~)等
• 赋值运算符:=及其与其它运算符结合的扩展赋值运算符,例如+=、%=。
• 操作符优先级:算术运算符 > 关系运算符 > 逻辑运算符 > 赋值运算符
变量
Scala有两种类型的变量
1)val:是不可变的,在声明时就必须被初始化,而且初始化以后就不能再赋值。
2)var:是可变的,声明的时候需要进行初始化,初始化以后还可以再次对其赋值。
基本语法:
val 变量名:数据类型 = 初始值
var 变量名:数据类型 = 初始值
但是,Scala有类型推断机制
输入和输出
控制台输入输出
从控制台读取数据
• 从控制台读取数据方法:readInt、readDouble、readByte、readShort、readFloat、readLong、readChar readBoolean及readLine,分别对应9种基本数据类型,其中前8种方法没有参数,readLine可以不提供参数,也可以带一个字符串参数的提示
• 所有这些函数都属于对象scala.io.StdIn的方法,使用前必须导入,或者直接用全称进行调用
向控制台输出信息方法
• print()和println(),可以直接输出字符串或者其它数据类型,其中println在末尾自动换行。
也有printf函数
s字符串和f字符串:Scala提供的字符串插值机制,以方便在字符串字面量中直接嵌入变量的值。
基本语法:
s " …$变量名… "
或
f " …$变量名%格式化字符… "
读写文件
写入文件
• Scala需要使用java.io.PrintWriter实现把数据写入到文件,PrintWriter类提供了print 和println两个写方法
读取文件
• 可以使用Scala.io.Source的getLines方法实现对文件中所有行的读取
控制结构
if条件表达式
和java类似
package cn.itcast.scala
object test {
def main(args: Array[String]) {
val x=3
if(x>0){
println("this is a positive number")
}else if(x==0){
println("this is a zero")
}else{
println("this is a negetive number")
}
}
}
有一点与Java不同的是,Scala中的if表达式的值可以赋值给变量
while循环
与Java完全相同
package cn.itcast.scala
object test {
def main(args: Array[String]) {
var i=9
while (i>0){
i-=1
printf("i is %d\n",i)
}
}
}
package cn.itcast.scala
object test {
def main(args: Array[String]) {
var i=0
do{
i+=1
println(i)
}while(i<5)
}
}
for循环
与Java的for循环相比,Scala的for循环在语法表示上有较大的区别,同时,for也不是while循环的一个替代者,而是提供了各种容器遍历的强大功能。
基本结构:
for (变量 <- 表达式) {语句块}
其中,
“变量<-表达式”
被称为“生成器(generator)”
for(i<- 1 to 5)
println(i)
for (j <- 1 to 10 by 2)
println(j)
此处,变量不需要关键字var或val进行声明。
1 to 10为一个整数的Range型容器,包含1到10.
守卫(guard)
“守卫(guard)”的表达式:过滤出一些满足条件的结果。基本语法:
for (变量 <- 表达式 if 条件表达式)
语句块
for (i <- 1 to 5 if i%2==0)
println(i)
上述语句等价于:
for (i<- 1 to 5)
if (i%2==0)
println(i)
注意:如果需要多个多虑条件,可以增加多个if语句,并用分号隔开。
Scala也支持“多个生成器”的情形,可以用分号把它们隔开,比如:
for(i <- 1 to 5;j <- 1 to 3)
println(i*j)
可以看出实际上实现了循环嵌套
For推导式
• for结构可以在每次执行的时候创造一个值,然后将包含了所有产生值的集合作为for循环表达式的结果返回,集合的类型由生成器中的集合类型确定。
•
for (变量 <- 表达式) yield {语句块}
对循环的控制
为了提前终止整个循环或者跳到下一个循环,Scala没有break和continue关键字。Scala提供了一个Breaks类(位于包scala.util.control)。Breaks类有两个方法用于对循环结构进行控制,即breakable和break:
将需要控制的语句块作为参数放在breakable后面,然后,其内部在某个条件满足时调用break方法,程序将跳出breakable方法。
数据结构
数组Array,元组Tuple,列表List,映射Map,集合Set
数组
数组:一种可变的、可索引的、元素具有相同类型的数据集合。
Scala提供了参数化类型的通用数组类Array[T],其中T可以是任意的Scala类型,可以通过显式指定类型或者通过隐式推断来实例化一个数组。
可以发现,没有使用new来生成对象,实际上是因为使用了Scala中的伴生对象的apply方法。
多维数组的创建:调用Array的ofDim方法
val myMatrix = Array.ofDim[Int](3,4) //类型实际就是Array[Array[Int]]
val myCube = Array.ofDim[String](3,2,4) //类型实际是Array[Array[Array[String]]]
可以使用多级圆括号来访问多维数组的元素,例如
myMatrix(0)(1)
返回第一行第二列的元素
元组
元组是对多个不同类型对象的一种简单封装。定义元组最简单的方法就是把多个元素用逗号分开并用圆括号包围起来。
使用下划线“_”加上从1开始的索引值,来访问元组的元素。
val tuple =("BigData",2021,8.24)
println(tuple._1) //返回BigData
如果需要在方法里返回多个不同类型的对象,Scala可以通过返回一个元组实现。
val (t1,t2,t3)=tuple
print(t1) //返回BigData
print(t2)
print(t3)
容器
Scala提供了一套丰富的容器(collection)库,包括序列(Sequence)、集合(Set)、映射(Map)等。
• Scala用了三个包来组织容器类,分别是scala.collection 、scala.collection.mutable和scala.collection.immutable。scala.collection包中的容器通常都具备对应的不可变实现和可变实现。
scala.collection包中容器的宏观层次结构:
序列
序列(Sequence): 元素可以按照特定的顺序访问的容器。序列中每个元素均带有一个从0开始计数的固定索引位置。
两种常用的序列:列表List和Range
(1)列表
• 列表: 一种共享相同类型的不可变的对象序列。定义在
scala.collection.immutable
包中
• 不同于Java的
java.util.List
,scala的List一旦被定义,其值就不能改变,因此声明List时必须初始化
• 列表有头部和尾部的概念,可以分别使用head和tail方法来获取
• head返回的是列表第一个元素的值
• tail返回的是除第一个元素外的其它值构成的新列表,这体现出列表具有递归的链表结构
•
strList.head
将返回字符串”BigData”,
strList.tail
返回
List ("Hadoop","Spark")
• 构造列表常用的方法是通过在已有列表前端增加元素,使用的操作符为
::
,例如:
val otherList="Apache"::strList
(2)Range
Range类:一种特殊的、带索引的不可变数字等差序列。其包含的值为从给定起点按一定步长增长(减小)到指定终点的所有数值。
集合set
• 不重复元素的容器(collection)。
• 列表中的元素是按照插入的先后顺序来组织的,但是,“集合”中的元素并不会记录元素的插入顺序,而是以“哈希”方法对元素的值进行组织,所以,它允许你快速地找到某个元素
• 集合包括可变集和不可变集,分别位于
scala.collection.mutable
包和
scala.collection.immutable
包,缺省情况下创建的是不可变集
var mySet = Set("Hadoop","Spark")
mySet += "Scala"
如果要声明一个可变集,则需要提前引入scala.collection.mutable.Set
import scala.collection.mutable.Set
val myMutableSet = Set("Database","BigData")
myMutableSet += "Cloud Computing"
映射Map
• 映射(Map):一系列键值对的容器。键是唯一的,但值不一定是唯一的。可以根据键来对值进行快速的检索
• Scala 的映射包含了可变的和不可变的两种版本,分别定义在包
scala.collection.mutable
和
scala.collection.immutable
里。默认情况下,Scala中使用不可变的映射。如果想使用可变映射,必须明确地导入
scala.collection.mutable.Map
如果要获取映射中的值,可以通过键来获取
对于这种访问方式,如果给定的键不存在,则会抛出异常,为此,访问前可以先调用contains方法确定键是否存在
迭代器Iterator
• 迭代器(Iterator)不是一个容器,而是提供了按顺序访问容器元素的数据结构。
• 迭代器包含两个基本操作:next和hasNext。next可以返回迭代器的下一个元素,hasNext用于检测是否还有下一个元素