Scala基础
简介
Scala是运行在 JVM 上的多范式编程语言,同时支持面向对象和面向函数编程,随着Spark和Kafka这样基于Scala的大数据框架的兴起,Scala逐步成为大数据行业编程的首选。
Scala的优势主要是:
- 开发大数据应用程序(Spark程序、Flink程序)
- 表达能力强,一行代码抵得上Java多行,开发速度快
- 兼容Java,可以访问庞大的Java类库
环境
- Scala程序运行在JVM之上,所以必须要有Java运行环境,Scala才能正确执行
- 安装JDK 1.8 版本,并配置好环境变量,注意:版本一定是JDK8,虽然现在已经到了JDK13
Java SE 8就是Java8,或者jdk1.8
- 下载Scala SDK,并配置环境变量
- 编译器仍然使用IDEA,需要安装Scala插件
插件在官网下载,要对应你的IDEA版本
插件的安装:【settings——plugins——Install Plugin From Disk】选择下载的压缩包即可!
- 使用IDEA新建工程,选择scala
语法
变量声明
val/var 变量名称:变量类型 = 初始值
val
定义的是不可重新赋值的变量(值不可修改)var
定义的是可重新赋值的变量(值可以修改)- 如果变量类型不显式声明则会自行推断
- scala的语句最后不需要添加分号
惰性变量
- scala中使用关键字
lazy
来定义惰性变量,实现延迟加载(懒加载) - 惰性变量只能是不可变变量,并且只有在调用时,才会去实例化这个变量
数据类型
基础类型 | 类型说明 |
---|---|
Byte | 8位带符号整数 |
Short | 16位带符号整数 |
Int | 32位带符号整数 |
Long | 64位带符号整数 |
Char | 16位无符号Unicode字符 |
String | Char类型的序列(字符串) |
Float | 32位单精度浮点数 |
Double | 64位双精度浮点数 |
Boolean | true或false |
- scala中所有的类型都使用大写字母开头
- 类型说明:
类型 | 说明 |
---|---|
Any | 所有类型的父类,,它有两个子类AnyRef与AnyVal |
AnyVal | 所有数值类型的父类 |
AnyRef | 所有对象类型(引用类型)的父类 |
Unit | 表示空,Unit是AnyVal的子类,它只有一个的实例(),它类似于Java中的void,但scala要比Java更加面向对象 |
Null | Null是AnyRef的子类,也就是说它是所有引用类型的子类。它的实例是null, 可以将null赋值给任何对象类型 |
Nothing | 所有类型的子类不能直接创建该类型实例,某个方法抛出异常时,返回的就是Nothing类型,因为Nothing是所有类的子类,那么它可以赋值为任何类型 |
条件表达式
- scala中的表达式都是有值的,可以理解为表达式是scala中的常用单元或“数据类型”
val x =1
val z = if(x>1) 1 else "error"
print(z) // error
块表达式
- 块表达式也是有值的
val result = {
val x=0
val y = x+10
val z = y+"-hello"
val m = z+"-kaikeba"
"over" // 最后的over赋给result
}
for循环
- 和go语言的语法很相似
val nums= 1 to 10
for(i <- nums) println(i)
// 双重for循环
for(i <- 1 to 3; j <- 1 to 3) println(i*10+j)
// 乘法表
for(i <- 1 to 9; j <- 1 to i){
print(i+"*"+j+"="+i*j+"\t")
if(i==j){
println()
}
}
- 守卫:for循环中的if判断
for(i <- 1 to 10 if i >5) println(i)
- 推导式:使用yield的for表达式,可以构建出一个集合
val v = for(i <- 1 to 5) yield i * 10
println(v) // Vector(10, 20, 30, 40, 50)
方法
def methodName (参数名:参数类型, 参数名:参数类型) : [return type] = {
// 方法体
}
- 参数列表的参数类型不能省略
- 返回值类型可以省略,根据方法体的最后一行值确定
- 在定义方法时可以给参数定义一个默认值
- 调用方法时,可以指定参数的名称传值
def add(a:Int,b:Int) = {
a+b
"value"
}
print(add(1,2)) // value
- 如果定义递归方法,不能省略返回值类型
def m1(x:Int):Int={
if (x==1) 1
else x*m1(x-1)
}
print(m1(10)) // 3628800
- 变长参数:
def add(num:Int*) = num.sum
print(add(1,2,3,4)) // 10
函数
- scala支持函数式编程,编写Spark/Flink程序会大量使用到函数
val 函数变量名 = (参数名:参数类型, 参数名:参数类型…) => 函数体
- 函数是一个对象(变量)
- 一个函数没有赋予一个变量,则称为匿名函数
- 无需指定返回值类型
val add = (x:Int, y:Int) => x + y
print(add(2,3))
数组
- scala中,有两种数组,一种是定长数组,另一种是变长数组
- 定长数组
// 通过指定长度定义数组
val/var 变量名 = new Array[元素类型](数组长度)
// 用元素直接初始化数组
val/var 变量名 = Array(元素1, 元素2, 元素3…)
val a = new Array[Int](10) // 长度为10的数组
a(0) = 666
print(a(0)) // 0
val b = Array("hadoop","spark","hive") // 初始化
print(b.length) // 3
- 变长数组
创建变长数组,需要提前导入ArrayBuffer类:
import scala.collection.mutable.ArrayBuffer
- 使用
+=
添加元素 - 使用
-=
删除元素 - 使用
++=
追加一个数组到变长数组
var c = ArrayBuffer[Int](666,888)
c += 999 // 追加
c -= 888 // 删除
c ++= a // 追加一个变长数组
print(c) // ArrayBuffer(666, 999, 666, 0, 0, 0, 0, 0, 0, 0, 0, 0)
- 遍历数组
for(i <- a)println(i)
for(i <- 0 to a.length -1 )println(a(i))
for(i <- 0 to a.length -1 )println(a(i)) // 0 until n ——生成一系列的数字,包含0,不包含n
- 数组常见操作
- 求和——sum方法
- 求最大值——max方法
- 求最小值——min方法
- 排序——sorted方法
array.sum
array.max
array.min
array.sorted
array.sorted.reverse
元组
- 元组可以用来包含一组不同类型的值
val/var 元组变量名称 = (元素1, 元素2, 元素3…)
val/var 元组变量名称 = 元素1->元素2 // 只有两个元素时
val a = (1, "张三", 20, "北京市")
val b = 1->2
// 访问元组中的元素_1、_2、_3....
print(a._1) // 1
Map
- Map可以称之为映射。它是由键值对组成的集合,scala当中的Map集合与java当中的Map类似
val/var map = Map(键->值, 键->值, 键->值…) // 推荐,可读性更好
- 不可变Map:
val map1 = Map("zhangsan"->30, "lisi"->40)
print(map1("zhangsan")) // 30
println(map1.getOrElse("wangwu", -1)) // 如果没有key,返回-1而不是保错
- 可变Map
import scala.collection.mutable.Map // 需要导包,语法相同
map1("zhangsan") = 50
map3 += ("wangwu" ->35) // 添加key-value
map3 -= "wangwu" // 删除key-value
println(map3.keys) // Set(zhangsan, wangwu)
println(map3.keySet) // Set(zhangsan, wangwu)
println(map3.values) // HashMap(50, 40)
// 遍历
for((k,v) <- map3) println(k+" -> "+v)
Set
- Set是代表没有重复元素的集合
- Set没有顺序
- 不可变集合
//创建一个空的不可变集
val/var 变量名 = Set[类型]()
//给定元素来创建一个不可变集
val/var 变量名 = Set[类型](元素1, 元素2, 元素3…)
- 可变集合
必须导入:import scala.collection.mutable.Set
创建方法和不可变集合相同
val set = Set(1,1,2,3,4,5)
println(set.size)
for(i <- set) println(i)
set += 6 //添加元素
set += (6,7,8,9) // 添加多个元素
println(set)
set -= 1 // 删除一个元素
set -= (9,10) // 删除多个元素
println(set)
set --= Set(2,3) // 删除一个集合
println(set)
set ++= Set(6,7,8) // 拼接两个集合
println(set)
println(set & Set(3,6))//求2个Set集合的交集
set.remove(8)
println(set)
List
- List是scala中最重要的、也是最常用的数据结构
- 有序、可重复
- 不可变列表:
val/var 变量名 = List(元素1, 元素2, 元素3...)
//使用 Nil 创建一个不可变的空列表
val/var 变量名 = Nil
//使用 :: 方法创建一个不可变列表
val/var 变量名 = 元素1 :: 元素2 :: Nil
- 可变列表
必须导入 :import scala.collection.mutable.ListBuffer
val list4 = ListBuffer[Int]()
val list = ListBuffer(1,2,3,4) // 带初始元素
println(list(0)) // 获取第一个元素
println(list.head) // 获取第一个元素
println(list.tail) // 获取除了第一个元素外其他元素组成的列表
println(list += 5) // 添加单个元素
println(list ++= List(6,7)) // 添加一个不可变的列表
println(list ++= ListBuffer(8,9)) //添加一个可变的列表(删除同样)
println(list.isEmpty) // 列表是否为空
list.toList //根据可变的列表生成不可变列表,原列表不变
list.toArray //根据可变的列表生成不可变数组,原列表不变
小结
这里总结了scala的基本语法,由于主要用于函数式编程,需要形成特殊的语法习惯,熟能生巧!
更加详细的介绍可以查看教程,很多细节不必死记硬背,只需要大致总结即可,比如数组、映射、集合、列表都有可变和不可变之分等,随着使用的深入了解原理才是目的。
要抓主要矛盾,解决主要矛盾,作为大数据编程的利器,下一节会介绍到Spark/Flink的大量业务代码都会使用到的函数式编程!