Scala 是一门多范式(multi-paradigm)的编程语言,设计初衷是要集成面向对象编程和函数式编程的各种特性。Scala 运行在 Java 虚拟机上,并兼容现有的 Java 程序。
下面是我的scala学习笔记连接:
一、开发环境安装
1、安装JDK
略
2、安装Scala SDK
安装的版本为Scala 2.11.12
下载地址:https://scala-lang.org/download/2.11.12.html
一路点击安装,注意安装路径不能有中文与空格!
踩个坑,如果安装之后输出:
因为默认安装路径在Program Files
文件,这里有有个空格,诶,卸载了重新安装一下
安装成功之后,打开CMD,输入scala -version
,输出对应的版本号,就算安装成功了,如下图所示:
3、安装IDEA Scala插件
打开idea,打开设置,找到Plugins,搜索Scala点击安装即可
二、变量
1、基本定义
Java变量定义:
int a = 0;
Scala变量定义:
val/var 变量标识:变量类型 = 初始值
其中:
val
:定义的是不可重新赋值的变量var
:定义的是可以重新赋值的变量
注意:
- Scala中定义变量类型写在变量名后面
- Scala的语句最后不需要添加分号
比如,定义一个变量:
val name:String = "wzq"
2、自动推断
Scala可以自动根据变量的值来自动推断变量的类型,这样编写代码更加简介
打开Scala编译器(win+R,输入scala):比如:
scala> var name = "wzq"
name: String = wzq
3、惰性赋值
当有一些变量保存的数据较大时,但是不需要马上加载到JVM
内存,可以使用惰性赋值来提高效率
语法格式:
lazy val/var 变量名 = 表达式
三、字符串
scala
提供多种定义字符串的方式,将来我们可以根据需要来选择最方便的定义方式,分别是:
-
使用双引号
val/var 变量名 = "字符串"
-
使用插值表达式,可以有效避免大量字符串的拼接
val/var 变量名 = s"${变量/表达式}字符串"
需要注意的是:
- 在定义字符串之前添加
s
- 在字符串中,可以使用
${}
来引用变量或者编写表达式
- 在定义字符串之前添加
-
使用三引号,如果有大段的文本需要保存,就可以使用三引号来定义字符串
val/var 变量名 = """字符串1 字符串2"""
四、数据类型与操作符
1、数据类型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QecVJO7q-1617962575671)(img/微信截图_20210408164610.png)]
与Java
的区别是:
- scala中所有的类型都是用大写字母开头
- 整形使用Int而不是Integer
- scala中定义变量可以不写类型,让scala编译器自动推断
2、运算符
- scala中没有 ++ – 运算符
- 与Java不一样,在scala中,可以直接使用 ==、 !=进行比较,他们与equals方法表示一致。而比较两个对象的引用值,使用eq
比如:
有一个字符串“abc“,再创建第二个字符串,值为:在第一个字符串后拼接一个空字符串
然后使用比较这两个字符串是否相等、再查看他们的引用值是否相等
var str1 = "abc"
var str2 = str1 + ""
str1 == str2
结果:res0: Boolean = true
str1.eq(str2)
结果:res1: Boolean = false
3、scala类型层次结构
五、条件表达式
就是判断,语法和Java一样,主要写一下跟Java不一样的地方:
1、有返回值的IF
- 在scala中,条件表达式也是有返回值的
- 在scala中,没有三元表达式,可以使用if表达式替代三元表达式
示例:
定义一个变量sex,再定义一个result变量,如果sex等于"male",result等于1,否则等于0
val sex = "male"
val result = if(sex == "male") 1 else 0
result: Int = 1
2、块表达式
- scala中,使用{}表示一个块表达式
- 和if表达式一样,块表达式也是有值的
- 值就是最后一个表达式的值
val a = {
| println("1 + 1")
| 1 + 1
| }
a = 2
六、循环
在scala中,可以使用for和while,但一般推荐使用for表达式,因为for表达式语法更简介
1、for表达式
语法:
for(i <- 表达式/数组/集合){
// 表达式
}
1)简单循环
使用for表达式打印1-10的数字:
步骤:
- 生成1-10的数字,使用to方法
- 使用for表达式遍历。打印每个数字
代码1:
val nums = 1.to(10)
for(i <- nums) println(i)
代码2:
for(i <- 1 to 10) println(i)
2)嵌套循环
使用for表达式,打印以下表达符
* * * * *
* * * * *
* * * * *
for(i <- 1 to 3 ; j <- 1 to 5){
print("* ");
if(j == 5)
println("")
}
3)守卫
for表达式中,可以添加if判断语句,这个if判断就称之为守卫,我们可以使用守卫让for表达式更简洁
语法:
for(i <- 表达式/数组/集合 if 表达式){
//表达式
}
示例:使用for表达式打印1-10之间能够整除3的数字:
for(i <- 1 to 10 if(i % 3 == 0)) println(i)
4)for推导式
- 将来可以使用for推导式生成一个新的集合(一组数据)
- 在for循环体中,可以使用yield表达式构建出一个集合,我们把yield的for表达式称为推导式
示例:生成一个10、20、30…100的集合
// for推导式:for表达式中以yield开始,该for表达式会构建出一个集合
val v = for(i<- 1 to 10) yield i * 10
2、while循环
语法与java保持一致
示例:打印1-10
var i = 1
while(i<=10){
| println(i)
| i = i + 1
| }
3、break和continue
- 在scala中,类似Java和C++的break/continue关键字被移除了
- 如果一定要使用break/continue,就需要使用scala.util.control包的Break类的breable和break方法
1)实现break
用法:
- 导入Breaks包 import scala.util.control.Breaks._
- 使用breakable将for表达式包起来
- for表达式中需要退出循环的地方,添加break()方法调用
示例:使用for表达式打印出1-100的数字,如果数字达到50,退出for表达式
import scala.util.control.Breaks._
breakable{
for(i <- 1 to 100){
if(i >= 50) break()
else println(i)
}
}
2)实现continue
与break类似,但是:
实现break式用breakable{}将整个for表达式包起来, 而实现continue使用breakable{}将for表达式的循环体包起来就可以了
示例:打印1-100的数字,使用for表达式来遍历,如果数字能整除10,不打印
import scala.util.control.Breaks._
for(i <- 1 to 100){
breakable{
if(i%10==0) break()
else println(i)
}
}
七、方法
一个类可以有自己的方法,scala中的方法和Java方法类似,但scala与Java定义方法的语法是不一样的。
1、定义方法
语法:
def methodName (参数名:参数类型,参数名:参数类型) : [return type] = {
//方法体
}
Notes:
- 参数列表的参数类型不能省略
- 返回值类型可以省略,由scala编译器自动推断
- 返回值可以不写return,默认就是{}块表达式的值
示例:
1、定义一个方法,实现两个整形数值相加,返回相加后的结果
2、调用该方法
代码:
def add(a:Int,b:Int) = a + b
scala> add(1,2)
res10: Inte = 3
2、返回值类型推断
scala定义方法可以省略返回值,由scala自动推断返回值类型,这样方法定义后更加简介
Attention
定义递归放啊,不能省略返回值类型
示例:定义一个递归方法求阶乘
def fac(a:Int) : Int = {
if(a <= 1) 1
else fac(a-1) * a
}
3、方法参数
scala中的方法参数,使用比较灵活,它支持以下几种类型的参数:
- 默认参数
- 带名参数
- 变长参数
1)默认参数
在定义方法时可以给一个参数定义一个默认值
示例:
1、 定义一个计算两个值相加的放啊,这两个值默认为0
2、调用该方法,不传任何参数
def add(x:Int=0,y:Int=0) = x + y
add()
scala> res0: Int = 0
2)带名参数
在调用方法时,可以指定参数的名称来进行调用
示例:
1、定义一个计算两个值相加的放啊,这两个值默认为0
2、调用该方法,只设置第一个参数的值
def add(x:Int=0,y:Int=0) = x+y
add(x=1)
3)变长参数
如果方法的参数是不固定的,可以定义一个方法的参数是变长参数
def 方法名(参数名:参数类型*):返回值类型 = {
方法体
}
Notes:
在参数类型后面加一个 * 号,表示参数可以是0个或者多个
示例:
1、定义一个计算若干个值相加的方法
2、调用方法,传入以下数据:1,2,3,4,5
def add(num:Int*) = num.sum
scala> add(1,2,3,4,5)
res1: Int = 15
4、方法调用方式
在scala中,有以下几种方法调用方式:
- 后缀调用法
- 中缀调用法
- 花括号调用法
- 无括号调用法
在后续编写spark、flink程序时,会使用到这些方法调用方式
1)后缀调用法
与Java没有区别:
对象名.方法名(参数)
示例:使用后缀法Math.abs
求绝对值
Math.abs(-1)
res0: Int = 1
2)中缀调用法
对象名 方法名 参数
例如:1 to 10
Tip
如果有多个参数,使用括号括起来
示例:使用中缀法Math.abs
求绝对值
Math abs -1
操作符即方法,所有的操作符都是方法
比如:1 + 1
在scala中,+ - * / %等这些操作符和Java一样,但在scala中
- 所有的操作符都是方法
- 操作符时一个方法名字是符号的方法
3)花括号调用法
Math.abs{
//表达式1
//表达式2
}
Atteantion
方法只有一个参数,才能使用花括号调用法
示例:使用花括号调用法Math.abs
求绝对值
Math.abs{-10}
res0: Int = 10
4)无括号调用法
如果方法没有参数,可以省略方法名后面的括号
示例:
- 定义一个无参数的方法,打印hellp
- 使用无括号调用法调用该方法
def m3() = println("hello")
m3
八、函数
scala支持函数式编程,将来写spark/flink程序中,会大量使用到函数
1、定义函数
val 函数变量名 = (参数名:参数类型,参数名:参数类型....) => 函数体
Tip
- 函数是一个对象(变量)
- 类似于方法,函数也有输入参数和返回值
- 函数定义不需要使用def定义
- 无需指定返回类型
示例:
1、定义一个两个数值相加的函数
2、调用该函数
val add = (x:Int=0,y:Int=0) => x+y
add(1,2)
res0 : Int = 3
2、方法和函数的区别
- 方法是隶属于类或者对象的,在运行时,它是加载到JVM的方法区中
- 可以将函数对象赋值给一个变量,在运行时,它是加载到JVM的堆内存中
- 函数是一个对象,继承自FunctionN,函数对象有apply | curried | toString | tupled这些方法,方法则没有
示例:方法无法赋值给变量
def add(x:Int,y:Int):Int = x + y
val a = add
<concole>:12: error: missing argument list for method add
...
3、方法转换为函数
- 有时候需要将方法转换为函数,作为变量传递,就需要将方法转换为函数
- 使用
_
即可将方法转换为函数
示例:
1、定义一个方法用来进行两个数相加
2、将该方法转换为一个函数,赋值给变量
def add(x:Int,y:Int):Int = x + y
val a = add _
九、数组
scala中数组的概念是和Java类似的,可以用数组来存放一组数据。scala中,有两种数组,一种是定长数组,另一种是变长数组
1、定长数组
- 定长数组指的是数组的长度是不允许改变的
- 数组的元素是可以改变的
语法:
// 通过指定长度定义数组
val/var 变量名 = new Array([元素类型](数组长度))
// 用元素直接初始化数组
val/var 变量名 = Array(元素1,元素2,元素3...)
Note
- 在scala中,数组的泛型使用 [] 来指定
- 使用()来获取元素
示例一:
1、定义一个长度为100的整形数组
2、设置第一个元素为110
3、打印第一个元素
val a = new Array(Int)(100)
a(0) = 110
println(a(0))
示例二:
1、定义一个包含以下元素的数组
"java","scala","python"
2、获取数组长度
val a = Array("java","scala","python")
a.length
2、变长数组
变长数组指的是数组的长度是可变的,可以往数组中添加、删除元素
1)定义变长数组
创建变长数组,需要提前导入ArrayBuffer类的import scala.collection.mutable.ArrayBuffer
语法:
-
创建空的ArrayBuffer变长数组,语法结构
val/var a = ArrayBuffer[元素类型]()
-
创建带有初始元素的ArrayBuffer
val/var = ArrayBuffer(元素1,元素2,元素3,...)
示例一:定义一个长度为0的整形变长数组
val a = ArrayBuffer[Int]()
示例二:定义一个包含以下元素的变长数组
"hadoop","strom","spark"
val a = ArrayBuffer("hadoop","strom","spark")
2)添加/修改/删除元素
- 使用
+=
添加元素 - 使用
-=
删除元素 - 使用
++=
追加一个数组到变长数组
示例:
1、定义一个变长数组,包含以下元素: “hadoop”,“spark”,“flink”
2、往该变长数组添加一个"flume"元素
3、从该变长数组删除"hadoop"元素
4、再将一个数组,该数组包含"hive","sqoop"追加到变长数组中
// 定义个变长数组
val a = ArrayBuffer("hadoop","spark","flink")
// 追加一个元素
a += "flume"
// 删除一个元素
a -= "hadoop"
// 插入数组
val b = ArrayBuffer("hive","sqoop")
a ++= b
// 修改元素
a(0) = "s"
3、遍历数组
可以使用下面两种方法来遍历数组:
- 使用for表达式直接遍历数组中的元素
- 使用索引遍历数组中的元素
示例一:
1、定义一个数组,包含1、2、3、4、5
2、使用for表达式直接遍历,并打印数组中的元素
val a = Array(1,2,3,4,5)
for(i<-a) println(i)
示例二:
1、定义一个数组,包含1、2、3、4、5
2、使用for表达式基于索引下标遍历,并打印数组的元素
val a = Array(1,2,3,4,5)
// to包含开始值和结束值
for(i <- 0 to a.length - 1) println(a(i))
// until包含开始值不包含结束值
for(i <- 0 until a.length) println(a(i))
4、数组常用算法
scala中的数组封装了一些常用的计算操作,将来在对数据处理的时候,不需要我们自己再重新实现,
以下为常用的几个算法
- 求和——sum方法
- 求最大值——max方法
- 求最小值——min方法
- 排序——sorted方法
- 反转——reverse方法
var a = Array(1,2,3,4,5)
a.sum
var a = Array(1,2,3,4,5)
a.max
var a = Array(1,2,3,4,5)
a.min
var a = Array(281,12,124,6,345)
//升序
a.sorted
//降序
a.sorted.reverse
十、元组
元组可以用来包含一组不同类型的值,例如:姓名、年龄、性别、出生年月,元组的元素是不可变的
1、定义元组
使用括号来定义元组
val/var 元组 = (元素1,元素2,元素3....)
使用箭头来定义元组(元组只有两个元素)
val/var 元组 = 元素1->元素2
示例:
定义一个元组,包含一个学生的以下数据
val a = (1,"zhangshan",20,"beijing")
示例:
- 定义一个元组,包含学生的姓名和年龄(zhangsan、20)
- 分别使用括号、和箭头来定义元组
val a = ("zhangsan",20)
val b = "zhangsan" -> 20
2、访问元组
使用_1 _2 _3 ...
来访问元组中的元素,_1
表示访问的第一个元素,以此类推
示例:
- 定义一个元组,包含一个学生的姓名和性别 “zhangsan”,“male”
- 分别获取该学生的姓名和性别
val a = "zhangsan" -> "male"
//获取第一个元素
a._1
十一、列表
列表是scala
中最重要的、也是最常用的数据结构,List
具备以下性质:
- 可以保存重复的值
- 有先后顺序
在scala中,也有两种列表,一种是不可变列表,另一种是可变列表
1、不可变列表
定义:不可变列表就是列表的元素、长度都是不可变的
使用List来创建
val/var 变量名 = List(元素1,元素2,元素3...)
使用Nil
创建一个不可变的空列表
val/var 变量名 = Nil
使用::
方法创建一个不可变列表
val/var 变量名 = 元素1 :: 元素2 :: Nil
Tip
使用
::
创建列表,最后必须是Nil
示例一:创建一个不可变列表,存放以下几个元素1,2,3,4
val a = List(1,2,3,4)
示例二:使用Nil
创建一个不可变的空列表
val a = Nil
示例三:使用::
方法创建列表,包含-2,-1
两个元素
val a = -2 :: -1 :: Nil
2、可变列表
可变列表就是列表的元素、长度都是可变的
要是有可变列表,先要导入import scala.collection.mutable.ListBuffer
Note
- 可变集合都在mutable包中
- 不可变集合都在immutable包中
1)定义
使用ListBuffer[元素类型]()
创建空的可变列表,语法:
val/var 变量名 = ListBuffer[Int]()
使用ListBuffer(元素1,元素2,元素3...)
创建可变列表,语法:
val/var 变量名 = ListBuffer(元素1,元素2,元素3...)
示例一:创建空的整形可变列表
val a = ListBuffer[Int]()
示例二:创建一个可变列表,包含1、2、3、4
val a = ListBuffer(1,2,3,4)
2)可变列表操作
- 获取元素(使用括号访问(索引值))
- 添加元素 +=
- 追加一个列表 ++=
- 更改元素(使用括号获取元素,然后进行赋值)
- 删除元素(-=)
- 转换为List(toList)
- 转换为Array(toArray)
import scala.collection.mutable.ListBuffer
val a = ListBuffer(1,2,3)
a(0)
a+=4
val b = ListBuffer(4,5,6)
a++=b
a-=7
a.toList
a.toArray
3、列表常用操作
以下是列表常用的操作:
-
判断列表是否为空(
isEmpty
) -
拼接两个列表(
++
) -
获取列表的首个元素(
head
)和剩余部分(tail
) -
反转列表(
reverse
) -
获取前缀(
take
)、获取后缀(drop
) -
扁平化(
flaten
)扁平化表示将列表中的列表中的所有元素放到一个列表中
-
拉链(
zip
)和拉开(unzip
)- 拉链:使用zip将两个列表,组合成一个元素为元组的列表
- 拉开:将一个包含元组的列表,解开成包含两个列表的元组
-
转换字符串(
toString
) -
生成字符串(
mkString
)- mkString方法,可以将元素以分隔符拼接起来,弄人没有分隔符
-
并集(
union
)—表示对两个列表取并集,不去重!使用distinct
可以去重 -
交集(
intersect
) -
差集(
diff
):获取a在b中不存在的元素
val a = List(1,2,3,4)
// 判断列表是否为空
a.isEmpty
res1: Boolean = false
//---------------------------------------------------------------
//拼接两个列表
val b = List(4,5,6)
a ++ b
res2: List[Int] = List(1,2,3,4,5,6)
//---------------------------------------------------------------
val a = List(1,2,4)
//获取首个元素
a.head
res3: Int = 1
//获取剩余部分
a.tail
res4: List[Int] = List(2,3)
//---------------------------------------------------------------
//反转列表
a.reverse
res5: List[Int] = List(3,2,1)
//---------------------------------------------------------------
//获取列表前缀和后缀
val a = List(1,2,3,4,5)
//获取前三个元素
a.take(3)
res6: List[Int] = List(1,2,3)
//获取后缀——除前三个以外的元素
a.drop(3)
res7: List[Int] = List(4,5)
//---------------------------------------------------------------
//扁平化
val a = List(List(1,2),List(3,4),List(5))
a.flatten
res8: List[Int] = List(1,2,3,4,5)
//---------------------------------------------------------------
val a = List("zhangsan","lisi","wangwu")
val b = List(19,20,21)
//拉链
a.zip(b)
res9: List[(String,Int)] = List((zhangsan,19),(lisi,20),(wangwu,21))
//拉开
res9.unzip()
res10: (List[String],List[Int]) = (List(zhangsan,lisi,wangwu),List(19,20,21))
//---------------------------------------------------------------
//转换字符串
val a = List(1,2,3,4)
println(a.toSting)
输出:List(1,2,3,4)
//---------------------------------------------------------------
//生成字符串
val a = List(1,2,3,4)
a.mkString
res11: String = 1234
a.mkString(":")
res12: String = 1:2:3:4
//---------------------------------------------------------------
//并集
val a = List(1,2,3,4)
val b = List(2,3,4,5)
a.union(b)
res13: List[Int] = List(1,2,3,4,2,3,4,5)
//并集去重
a.union(b).distinct
res14: List[Int] = List(1,2,3,4,5)
//---------------------------------------------------------------
//交集
val a = List(1,2,3,4)
val b = List(3,4,5,6)
a.intersect(b)
res15: List[Int] = List(3,4)
//---------------------------------------------------------------
//差集
val a = List(1,2,3,4)
val b = List(3,4,5,6)
a.diss(b)
res16: List[Int] = List(1,2)
十二、集
Set
是代表没有重复元素的集合,Set具有以下性质:
- 元素不重复
- 不保证插入顺序
scala中的集分为两种:可变集 与 不可变集
1、不可变集
定义:创建一个空的不可变集,语法格式:
val/var 变量名 = Set[类型]()
给定元素来创建一个不可变集,语法格式:
val/var 变量名 = Set(元素1,元素2,元素3...)
基本操作:
- 获取集的大小(
size
) - 遍历集(和遍历数组一致)
- 添加一个元素,生成一个Set(
+
) - 拼接两个集,生成一个Set(
++
) - 拼接集合列表,生成一个Set(
++
)
2、可变集
定义:可变集合不可变集的创建方式一致,只不过需要提前导入一个可变集类
导入:import scala.collection.mutable.Set
示例:
1、定义一个可变集,包含以下元素:1,2,3,4
2、添加元素5到可变集中
3、从可变集中移除元素1
val a = Set(1,2,3,4)
//添加元素
a+=5
//删除元素
a-=1
十三、映射
Map可以称之为映射,它是由键值对组成的集合,在scala中,Map也分为不可变Map和可变Map
1、不可变Map
语法:
val/var map = Map(键->值,键->值,键->值...) //推荐,可读性好
val/var map = Map((键,值),(键,值),(键,值)...)
val map = Map("zhangsan"->30)
2、可变Map
定义语法和不可变Map一致,但定义可变Map需要手动导入import scala.collection.mutable.Map
val map = Map("zhangsan"->30,"lisi"->40)
map("zhangsan") = 20
十四、iterator迭代器
scala针对每一类集合都提供一个迭代器iterator用来迭代访问集合
使用iterator来遍历:
- 使用
iterator
方法可以从集合获取一个迭代器 - 迭代器的两个基本操作
- hasNext——查询容器中是否有下一个元素
- next——返回迭代器的下一个元素,如果没有,抛出
NoSuchElementException
- 每一个迭代器都是有状态的
- 迭代完后保留在最后一个元素的位置
- 再次使用则抛出
NoSuchElementException
- 可以使用while或者for来逐个返回元素
val a = List(1,2,3,4)
val ite = a.iterator
while(ite.hasNext){
println(ite.next)
}
for(i <- ite) println(i)