Scala
是一种多范式的编程语言,其设计的初衷是要集成面向对象编程和函数式编程的各种特性。Scala
运行于Java
平台(JVM
虚拟机),并兼容现有的Java
程序
Scala
的特点
优雅:这是框架设计师第一个要考虑的问题,框架的用户是应用开发程序员,API
是否优雅直接影响用户体验。
速度快:Scala
语言表达能力强,一行代码抵得上Java
多行,开发速度快;Scala
是静态编译的,所以和JRuby
,Groovy
比起来速度会快很多。
能融合到Hadoop
生态圈:Hadoop
现在是大数据事实标准,Spark
并不是要取代Hadoop
,而是要完善Hadoop
生态。JVM
语言大部分可能会想到Java
,但Java
做出来的API
太丑,或者想实现一个优雅的API
太费劲。
Scala
是函数式编程,那么函数式编程和命令式编程的不同点是什么?
命令式编程涉及多线程之间的状态共享,需要锁机制实现并发控制
函数式编程不会再多个线程之间共享状态,不需要用锁机制,可以更好的并行处理,充分利用多核CPU
并行处理。
跳转顶部
Scala
中操作符就是方法:a 方法 b
等价于a.方法(b)
val sum1 = 3 + 5
val sum2 = (3).+(5)
println(sum1 == sum2) //true
+
看作是一个方法富包装类型
对于基本数据类型,除了以上提到的各种操作符外,Scala还提供了许多常用运算的方法,只是这些方法不是在基本类里面定义,而是被封装到一个对应的富包装类中
每个基本类型都有一个对应的富包装类,例如In
t有一个RichInt
类、String
有 一个RichString
类,这些类位于包scala.runtime
中
当对一个基本数据类型的对象调用其富包装类提供的方法,Scala会自动通过隐式转换将该对象转换为对应的富包装类型,然后再调用相应的方法。例如: 3 max 5
变量
val
:不可变的,在声明的时候就必须初始化,并且在初始化之后不可以在赋值var
:是可变的,在声明的时候需要进行初始化,但是后面还是可以对值来进行更改的//不可变
val a = 10
//可变
var b = "s"
Scala
中由类型推断机制:即根据初始值自动推断变量的类型,使得自定义变量时可以省略具体的数据类型从控制台读入数据方法: readInt
、 readDouble
、 readByte
、readShort
、readFloat
、 readLong
、readChar
、readBoolean
及readLine
,分别对应9种基本数据类型,其中前8种方法没有参数,readLine可以不提供参数,也可以带一个字符串参数的提示
所有这些函数都属于对象scala.io.StdIn
的方法,使用前必.须导入,或者直接用全称进行调用
C语言风格格式字符串的printf()
函数
s字符串和f字符串:Scala提供的字符串插值机制,以方便在字符串字面量中直接嵌入变量的值。
基本语法:s " … 变 量 名 … " 或 f " … 变量名… " 或 f " … 变量名…"或f"…变量名%格式化字符… "
Scala
需要使用java.io.PrintWriter
实现把数据写入到文件,PrintWriter
类提供了print
和println
两个写方法
可以使用scala.io.Source
的getLines
方法实现对文件中所有行的读取
val fileInput = Source.fromFile("dataset/test.txt")
val lines = fileInput.getLines()//得到的是一个迭代器
for (line <- lines) println(line)
跳转顶部
if
条件表达式
if(表达式){
语句块1
}else if(表达式){
语句块2
}else{
语句块3
}
Scala
与Java
不同的一点就是表达式可以赋值给变量
var num = 5
val a = if (num > 4) 1 else -1
println(a)
while
循环的结构,do while
循环的特点是,不管是否满足条件,他必定至少执行一次
while(表达式){
循环体
}
//或者
do{
循环体
}while(表达式)
跳转顶部
案例演示
var i = 9
while (i > 0) {
i -= 1
printf("i is %d\n", i)
}
var x = 0
do {
x += 1
println(x)
} while (x < 5)
for
循环基本语句
for(变量<-表达式){语句块}
其中变量<-表达式
被称为生成器
只有单个生成器的for
循环
//循环输出1-5
for (i <- 1 to 5) println(i)
//跳着输出
for (i <- 1 to 5 by 2) println(i)
//跳着输出且过滤
for (i <- 1 to 5 by 2 if i%2==0)println(i)
多个生成器,输出的次数是满足每个生成器的乘积
for (i <- 1 to 5; j <- 1 to 3) println(i * j)
var r = for (i <- Array(1, 2, 3, 4, 5) if i % 2 == 0) yield {
println(i); i
}
r.foreach(println(_))
scala
中的break
和continue
为了提前终止整个循环或者跳到下一个循环,Scala
没有break
和continue
关键字
Scala
提供了一个Breaks
类(位于包scala.util.control
)。Breaks
类有两个方法用于对循环结构进行控制,即breakable
和break
val array = Array(1, 3, 10, 5, 4)
breakable {
for (i <- array) {
if (i > 5) break
println(i)
}
}
println("**********************")
for (i <- array) {
breakable {
if (i > 5) break
println(i)
}
}
数组是一种可变的、可索引的、元素具有相同类型的数据集合
数据的申明如下
val intValueArr = new Array[Int](3) //声明一个长度为3的整型数组,每个数组元素初始化为0
intValueArr(0) = 12 //给第1个数组元素赋值为12
intValueArr(1) = 45 //给第2个数组元素赋值为45
intValueArr(2) = 33 //给第3个数组元素赋值为33
val myStrArr = new Array[String](3) //声明一个长度为3的字符串数组,每个数组元素初始化为null
myStrArr(0) = "BigData"
myStrArr(1) = "Hadoop"
myStrArr(2) = "Spark"
for (i <- 0 to 2) println(myStrArr(i))
数组可以不给出类型,Scala
会自己根据初始化的数据来推断出数据的类型
val intValueArr = Array(1,2,3)
多维数组的创建
//多维数组的创建
val myMatrix = Array.ofDim[Int](3,4) //类型实际就是Array[Array[Int]]
val myCube = Array.ofDim[String](3,2,4) //类型实际是Array[Array[Array[Int]]]
//访问第一行第二列的元素
println(myMatrix(0)(1))
元组是对多个不同类型对象的一种简单封装。定义元组最简单的方法就是把多个元素用逗号分开并用圆括号包围起来。使用下划线“_”加上从1开始的索引值,来访问元组的元素
元组的基本定义和使用
val tuple = ("BigData",2022,2.022)
println(tuple._1)
println(tuple._3)
Scala
提供了一套丰富的容器(collection
)库,包括序列(Sequence
)、集合(Set
)、映射(Map
)等
Scala
用了三个包来组织容器类,分别是scala.collection
、scala.collection.mutable
和scala.collection.immutable
scala.collection
封装了可变容器和不可变容器的超类或特质,定义了可变容器和不可变容器的一些通用操作
序列(Sequence
): 元素可以按照特定的顺序访问的容器。序列中每个元素均带有一个从0开始计数的固定索引位置
序列容器的根是collection.Seq
特质。其具有两个子特质 LinearSeq
和IndexedSeq
。LinearSeq
序列具有高效的 head
和 tail
操作,而IndexedSeq
序列具有高效的随机存储操作
实现了特质LinearSeq
的常用序列有列表(List
)和队列(Queue
)。实现了特质IndexedSeq
的常用序列有可变数组(ArrayBuffer
)和向量(Vector
)
列表: 一种共享相同类型的不可变的对象序列。定义在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)等效
注意:除了head
、tail
操作是常数时间O(1)
,其它按索引访问的操作都需要从头开始遍历,因此是线性时间复杂度O(N)。
Range
是一种特殊的、带索引的不可变的数字等差序列
//创建1-5的数值序列
val r = new Range(1,5,1)
val r1 = 1 to 5
//1-5且不包含5的序列
val r2 = 1 until 5
//1-10,包含终点步长为2的
val r3 = 1 to 10 by 2
//创建一个Float类型的数值序列,从0.5f到5.9f,步长为0.3f
val r4 = 0.5f to 5.9f by 0.3f
集合:元素不重复的容器
列表这元素是按照插入的先后顺序来组织的,但是,集合这元素并不会记录元素的插入顺序,而是以哈希方法对元素的值进行组织,所以,他允许快速第找到某个元素
集合包括可变集合和不可变集合,默认创建的是不可变集合,如需要创建可变集合需要导入scala.collection.mutable.Set
//不可变
var mySet = Set("Hadoop","Spark")
mySet+="Spark"
println(mySet)
//可变
import scala.collection.mutable.Set
val myMutableSet = Set("Big","Data")
myMutableSet+="Set"
println(myMutableSet)
映射:一系列键值对的容器。键是唯一的,但是值不一定是唯一的。可以根据键来对值进行快速的检索
val map = Map("name" -> "张三", "id" -> "1", "age" -> "20")
println(map("name"))
为了给定的键不存在而报错,可以这样
val name = if (map.contains("name")) map("name") else 0;println(name)
迭代器不是一个容器而是提供了按顺序访问容器的数据结构
val iter = Iterator("Hadoop","Spark","Scala")
while (iter.hasNext) {
println(iter.next())
}
跳转顶部