本篇博客主要了解基础重要的Scala语法,为 spark 的学习打下基础。
1、基本语法
1.1 声明值和变量
Scala有两种类型的变量:
- val: 是不可变的,在声明时就必须被初始化,而且初始化以后就不能再赋值;
- var: 是可变的,声明的时候需要进行初始化,初始化以后还可以再次对其赋值。
1.2 基本数据类型和操作
- Scala的数据类型包括:Byte、Char、Short、Int、Long、Float、Double和Boolean
- 和Java不同的是,在Scala中,这些类型都是“类”,并且都是包scala的成员,比如,Int的全名是scala.Int。对于字符串,Scala用java.lang.String类来表示字符串
操作符:在Scala中,可以使用加(+)、减(-)、乘(*)、除(/)、余数(%)等操作符,而且,这些操作符就是方法。例如,5+3和(5).+(3)是等价的,也就是说:
a 方法 b 等价于 a.方法(b)
前者是后者的简写形式,这里的+是方法名,是Int类中的一个方法。
需要注意的是:和Java不同,在Scala中没有提供递增 递减 ++, -- 操作符,可以使用 += 、-= 方式进行表达
富包装类
- ·对于基本数据类型,除了以上提到的各种操作符外,Scala还提供了许多常用运算的方法,只是这些方法不是在基本类里面定义,还是被封装到一个对应的富包装类中
- 每个基本类型都有一个对应的富包装类,例如 Int 有一个 RichInt 类、String 有一个 RichString 类,这些类位于包 scala.runtime 中
- ·当对一个基本数据类型的对象调用其富包装类提供的方法,Scala会自动通过隐式转换将该对象转换为对应的富包装类型,然后再调用相应的方法。例如: 3 max 5
1.3 Range
- 在执行for循坏时,我们经常会用到数值序列,比如,i 的值从1循环到5,这时就可以采用 Range 来实现
- Range可以支持创建不同数据类型的数值序列,包括 Int、Long、Float、Double、Char、BigInt 和 BigDecimal 等
举例说明:
(1)创建一个从1到5的数值序列,包含区间终点5,步长为1
(2)创建一个从1到5的数值序列,不包含区间终点5,步长为1
(3)创建一个从1到10的数值序列,包含区间终点10,步长为2
(4)创建一个Float类型的数值序列,从0.5f到5.9f,步长为0.3f
1.4 控制台输入输出语句
- 为了从控制台读写数据,可以使用以read为前缀的方法,包括: readInt、readDouble、readByte、readShort、readFloat、readLong、readChar readBoolean及readLine,分别对应9种基本数据类型,其中前8种方法没有参数,readLine可以不提供参数,也可以带一个字符串参数的提示
- 所有这些函数都属于对象scala.io.StdIn的方法,使用前必须导入,或者直接用全称进行调用
为了向控制台输出信息,常用的两个函数是 print()和println() , 可以直接输出字符串或者其它数据类型
Scala还带有C语言风格的格式化字符串的printf()函数
print()、println() 和 printf() 都在对象 Predef 中定义,该对象默认情况下被所有 Scala 程序引用,因此可以直接使用 Predef 对象提供的方法,而无需使用 scala.Predef. 的形式
1.5 读写文件
写入文件
Scala需要使用 java.io.PrintWriter 实现把数据写入到文件。
如果我们想把文件保存到一个指定的目录下,就需要给出文件路径
读取文件
可以使用 Scala.io.Source 的 getLines 方法实现对文件中所有行的读取。
1.6 异常处理
2、控制结构
2.1 if 条件表达式
基本使用与Java一样,但有一点与Java不同的是,Scala 中的 if 表达式的值可以赋值给变量。
2.2 while 循环
和 Java 语法一样,分为 while 和 do while。
2.3 for 循环
Scala中的for循环语句格式如下:for ( 变量 <- 表达式 ) 语句块
其中,“变量<-表达式”被称为“生成器(generator)”
- 不希望打印出所有的结果,过滤出一些满足制定条件的结果,需要使用到称为“守卫(guard)”的表达式
- 比如,只输出1到5之中的所有偶数,可以采用以下语句:
Scala也支持“多个生成器”的情形,可以用分号把它们隔开,比如:
可以给每个生成器都添加一个“守卫”,如下:
for 推导
- Scala的 for 结构可以在每次执行的时候创造一个值,然后将包含了所有产生值的集合作为for循环表达式的结果返回,集合的类型由生成器中的集合类型确定
- 通过 for 循环遍历一个或多个集合,对集合中的元素进行“推导”,从而计算得到新的集合,用于后续的其他处理
for(变量<-表达式) yield {语句块}
3、数据结构
3.1容器(Collection)
- Scala提供了一套丰富的容器(collection)库,包括列表(List)、数组(Array)、集合( Set)、映射(Map)等
- 根据容器中元素的组织方式和操作方式,可以区分为 有序 和 无序、可变 和 不可变 等不同的容器类别
- Scala用了三个包来组织容器类,分别是scala.collection 、scala.collection.mutable 和 scala.collection.immutable
下图显示了scala.collection包中所有的容器类。这些都是高级抽象类或特质。例如,所有容器类的基本特质(trait)是Traverable特质,它为所有的容器类定义了公用的foreach方法,用于对容器元素进行遍历操作
下面的图表显示了scala.collection.immutable中的所有容器类
下面的图表显示scala.collection.mutable中的所有容器类
3.2列表(List)
- 列表是一种共享相同类型的不可变的对象序列。既然是一个不可变的集合,Scala的List定义在scala.collection.immutable包中
- 不同于Java的java.util.List,scala的List一旦被定义,其值就不能改变,因此声叨List时必须初始化
- var strList=List("BigData","Hadoop","Spark")
- 列表有头部和尾部的概念,可以分别使用head和tail方法来获取
- head返回的是列表第一个元素的值
- tail返回的是除第一个元素外的其它值构成的新列表,这体现出列表具有递归的链表结构
- strList.head将返回字符串”BigData”,strList.tail返回List("Hadoop","Spark")
构造列表常用的方法是通过在已有列表前端增加元素,使用的操作符为 :: ,例如:
val otherList = "Apache" :: strList
执行该语句后strList保持不变,而otherList将成为一个新的列表:
List("Apache","BigData","Hadoop","Spark")
Scala还定义了一个空列表对象Nil,借助Nil,可以将多个元素用操作符 :: 串起来初始化一个列表
val intList = 1::2::3::Nil 与val intList = List(1,2,3)等效
3.3集合(Set)
- 集合(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"
3.4映射(Map)
- 映射(Map)是一系列键值对的容器。在一个映射中,键是唯一的,但值不一定是唯一的。可以根据键来对值进行快速的检索
- 和集合一样,Scala采用了类继承机制提供了可变的和不可变的两种版本的映射,分别定义在包scala.collection.mutable和scala.collection.immutable 里。默认情况下,Scala中使用不可变的映射。如果想使用可变映射,必须明确地导入scala.collection.mutable.Map
val university = Map("XMU" -> "Xiamen University","THU" ->"Tsinghua University", "PKU"->"PekingUniversity")
获取值:university("XMU")
对于这种访问方式,如果给定的键不存在,则会抛出异常,为此,访问前可以先调用contains方法确定键是否存在。
不可变映射,是无法更新映射中的元素的,也无法增加新的元素。如果要更新映射的元素,就需要定义一个可变的映射
也可以使用 += 操作添加新的元素
循环遍历映射
3.5迭代器( lterator)
- 在Scala中,迭代器( lterator)不是一个集合,但是,提供了访问集合的一种方法
- 迭代器包含两个基本操作: next 和 hasNext。next 可以返回迭代器的下一个元素,hasNext 用于检测是否还有下一个元素
3.6数组(Array)
数组是一种可变的、可索引的、元素具有相同类型的数据集合,它是各种高级语言中最常用的数据结构。Scala提供了参数化类型的通用数组类 Array[T],其中 T 可以是任意的Scala类型,可以通过显式指定类型或者通过隐式推断来实例化一个数组。
Array提供了函数ofDim来定义二维和三维数组,用法如下:
val myMatrix = Array.ofDim[Int](3,4) // 类型实际就是 Array [ Array [ lnt ] ]
val myCube = Array.ofDim[String](3,2,4)// 类型实际是Array[Array[Array[Int]]
可以使用多级圆括号来访问多维数组的元素,例如myMatrix(O)(1)返回第一行第二列的元素
采用Array类型定义的数组属于定长数组,其数组长度在初始化后就不能改变。如果要定义变长数组,需要使用ArrayBuffer参数类型,其位于包 scala.collection.mutable 中。举例如下:
import scala.collection.mutable.ArrayBufferval val aMutableArr = ArrayBuffer(10,20,30) aMutableArr += 40 aMutableArr.insert(2,60,40) aMutableArr -= 40 var temp=aMutableArr.remove(2)
3.7元组(Tuple)
元组是不同类型的值的聚集。元组和列表不同,列表中各个元素必须是相同类型,而元组可以包含不同类型的元素
基础语法介绍到这里,下篇博客总结 Scala的面向对象 与 函数式 编程。