Scala基础语法学习
Posted 捡黄金的少年
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Scala基础语法学习相关的知识,希望对你有一定的参考价值。
目录
如果子类要覆盖父类中的一个非抽象方法,必须要使用override关键字
一、变量
val/var 变量名称:变量类型 = 初始值
注意:
-
val
定义的是不可重新赋值的变量(值不可修改) -
var
定义的是可重新赋值的变量(值可以修改)
-
scala中声明变量是变量名称在前,变量类型在后,跟java是正好相反
-
scala的语句最后不需要添加分号、、
惰性变量
-
Scala中使用==关键字lazy==来定义惰性变量,实现延迟加载(懒加载)。
-
惰性变量只能是不可变变量,并且只有在调用惰性变量时,才会去实例化这个变量。
-
语法格式
lazy val 变量名 = 表达式
二、数据类型
基础类型 | 类型说明 |
---|---|
Byte | 8位带符号整数 |
Short | 16位带符号整数 |
Int | 32位带符号整数 |
Long | 64位带符号整数 |
Char | 16位无符号Unicode字符 |
String | Char类型的序列(字符串) |
Float | 32位单精度浮点数 |
Double | 64位双精度浮点数 |
Boolean | true或false |
1. scala中所有的类型都使用大写字母开头,说明是它是“类”
2. 整形使用Int而不是Integer
3. scala中定义变量可以不写类型,让scala编译器自动推断
三、scala中的条件表达式
1、if表达式
这个和java差不多,可以加括号,或者不加括号
def main(args: Array[String]): Unit =
val x:Int=2
if (x>10) println(x)
else println(x+x)
打印为2
2、块表达式
定义变量时用 包含一系列表达式,其中块的最后一个表达式的值就是块的值
def main(args: Array[String]): Unit =
val x = 0
val result =
val y = x + 10
val z = y + "-hello"
val m = z + "-kaikeba"
"over"
println(result)
打印结果
over
Process finished with exit code 0
返回值就是m了
def main(args: Array[String]): Unit =
val x = 0
val result =
val y = x + 10
val z = y + "-hello"
val m = z + "-kaikeba"
m
println(result)
打印结果
10-hello-kaikeba
四、循环
在scala中,可以使用for和while,但一般推荐使用for表达式,因为for表达式语法更简洁
for (i <- 表达式/数组/集合)
//表达式
1、简单for循环
def main(args: Array[String]): Unit =
var nums=1 to 10
//for循环
for(i <- nums) println(i)
2、双层for循环
def main(args: Array[String]): Unit =
//双层for循环
for (i <- 1 to 3; j <- 1 to 3)
println(i * 10 + j)
打印的值为
11
12
13
21
22
23
31
32
33
3、守卫:在for表达式中可以添加if判断语句,这个if判断称为守卫
def main(args: Array[String]): Unit =
// 守卫
var nums = 1 to 10
for (i <- nums if i>5 ) println(i)
打印的值为:
6
7
8
9
10
4、yield表达式
在for循环体中,以yield表达式开始,这类循环能构建出一个新的集合,我们把这类循环称为推导式
def main(args: Array[String]): Unit =
// for推导式:for表达式中以yield开始,该for表达式会构建出一个集合
val v = for(i <- 1 to 5) yield i * 10
//打印集合v的第一个元素
println(v(0))
打印的值为
10
五、while循环
while(返回值为布尔类型的表达式)
//表达式
六、方法
def methodName (参数名:参数类型, 参数名:参数类型) : [return type] =
// 方法体:一系列的代码
-
参数列表的参数类型不能省略
-
返回值类型可以省略,由scala编译器自动推断
-
返回值可以不写return,默认就是块表达式的值
-
注意:
-
如果定义递归方法,必须指定返回值类型
-
示例:(方法三)
-
定义递归方法(求阶乘)
-
10 * 9 * 8 * 7 * 6 * ... * 1
//方法一
def yy(i: Int = 10, u: Int = 8): Int =
return i + u;
//方法二
def tt(i: Int) = i * i
/**
* 递归必须添加返回值参数
*
* @param x
* @return
*/
//方法三
def m1(x: Int): Int =
if (x == 1) 1
else x * m1(x - 1)
/**
* 参数值加*,可以传递多个参数
*
* @param num
* @return
*/
// 方法四
def add(num: Int*) = num.sum
def main(args: Array[String]): Unit =
println(yy(1))
println(tt(8))
println(m1(10))
println(add(1,2,3))
打印的值为
9
64
3628800
6
6、函数
-
函数在scala中属于头等公民
-
数字能做的事,函数也可以
-
数字可以作为参数,所以函数也可以作为其他方法或函数的参数
-
数字可以作为返回值,所以函数也可以作为其他方法或函数的返回值
-
数字可以赋值给一个变量,所以函数也可以赋值给一个变量
-
-
scala支持函数式编程,将来编写Spark/Flink程序中,会大量使用到函数
-
语法
val 函数变量名 = (参数名:参数类型, 参数名:参数类型....) => 函数体
注意
-
函数是一个对象(变量)
-
类似于方法,函数也有输入参数和返回值
-
函数定义不需要使用def定义
-
无需指定返回值类型
val add2 = (x: Int, y: Int) => x * y
def main(args: Array[String]): Unit =
println(add2(2,4))
打印的值为
8
方法和函数的区别
-
方法是隶属于类或者对象的,在运行时,它是加载到JVM的==方法区==中
-
可以将函数对象赋值给一个变量,在运行时,它是加载到JVM的==堆内存==中
-
函数是一个对象,继承自FunctionN,函数对象有apply,curried,toString,tupled这些方法,而方法则没有
方法转换为函数
-
有时候需要将方法转换为函数,作为变量传递,就需要将方法转换为函数
-
使用
_
即可将方法转换为函数(记得空格) -
//方法三 def m1(x: Int): Int = if (x == 1) 1 else x * m1(x - 1) val hanshu=m1 _; def main(args: Array[String]): Unit = println(hanshu(10))
打印的结果
-
3628800
7、数组
-
scala中数组的概念是和Java类似,可以用数组来存放同类型的一组数据
-
scala中,有两种数组,一种是定长数组,另一种是变长数组
(1)、定长数组
-
定长数组指的是数组的长度是不允许改变的
-
数组的元素是可以改变的
demo如下
def main(args: Array[String]): Unit =
val a = new Array[Int](10)
println(a)
a(0)=98
println(a(0))
println(a(1))
println(a.length)
打印的值为:
[I@ea4a92b
98
0
10
(2)、变长数组
-
变长数组指的是数组的长度是可变的,可以往数组中添加、删除元素
-
创建变长数组,需要提前导入ArrayBuffer类
import scala.collection.mutable.ArrayBuffer
语法
-
创建空的ArrayBuffer变长数组
-
val/var a = ArrayBuffer[元素类型]()
创建带有初始元素的ArrayBuffer
-
val/var a = ArrayBuffer(元素1,元素2,元素3....)
变长数组的增删改操作
-
使用
+=
添加元素 -
使用
-=
删除元素 -
使用
++=
追加一个数组到变长数组
demo如下
def main(args: Array[String]): Unit =
//变长数组
val a = ArrayBuffer[String]();
a+=("test")
a+=("张三")
a++=Array("妞儿","所以算是")
println(a(3))
println(a.size)
打印的值为
所以算是
4
(3)、遍历数组
可以使用以下两种方式来遍历数组:
-
使用==for表达式== 直接遍历数组中的元素
-
使用 ==索引== 获得数组中的元素
for(i <- a) println(i)
/0 to n ——包含0,也包含n
for(i <- 0 to a.length -1 ) println(a(i))
//0 until n ——生成一系列的数字,包含0,不包含n
for(i <- 0 until a.length) println(a(i))
(4)、数组常用操作
scala中的数组封装了丰富的计算操作,将来在对数据处理的时候,不需要我们自己再重新实现。
-
求和——sum方法
-
求最大值——max方法
-
求最小值——min方法
-
排序——sorted方法
def main(args: Array[String]): Unit =
val array = Array(1,3,4,2,5)
println("求和:"+array.sum)
println("最大值:"+array.max)
println("最小值:"+array.min)
println("排序(获取一个新数组,并翻转):"+array.sorted.reverse(0))
打印如下
求和:15
最大值:5
最小值:1
排序(获取一个新数组,并翻转):5
8、元组
元组可以用来包含一组不同类型的值。例如:姓名,年龄,性别,出生年月。
元组的元素是不可变的。
1、定义元组
使用括号来定义元组
val/var 元组变量名称 = (元素1, 元素2, 元素3....)
使用箭头来定义元素(元组只有两个元素 )
val/var 元组 = 元素1 -> 元素2
2、访问元组
-
使用
_1、_2、_3....
来访问元组中的元素 -
元组的index从1开始,_1表示访问第一个元素,依次类推
def main(args: Array[String]): Unit =
val a = (1, "张三", 20, "北京市")
val b = 1 -> 2
println(a._1)
println(a._4)
println(b._1)
打印的值为
1
北京市
1
9、映射Map
-
Map可以称之为映射。它是由键值对组成的集合。scala当中的Map集合与java当中的Map类似,也是key,value对形式的。
-
在scala中,Map也分为不可变Map和可变 Map。
(1)、不可变map
定义语法
val/var map = Map(键->值, 键->值, 键->值...) // 推荐这种写法,可读性更好
val/var map = Map((键, 值), (键, 值), (键, 值), (键, 值)...)
def main(args: Array[String]): Unit =
val map1 = Map("zhangsan"->30, "lisi"->40)
val map2 = Map(("zhangsan", 30), ("lisi", 30))
println(map1("lisi"))
println(map2("zhangsan"))
打印的值为
40
30
(2)、可变Map
1、导包
import scala.collection.mutable.Map
def main(args: Array[String]): Unit =
val map3 = Map("zhangsan" -> 30, "lisi" -> 40)
//修改一个
map3("zhangsan") = 50
println("修改的" + map3)
//添加一个
map3 += ("yy" -> 22)
println("添加的" + map3)
//删去一个
map3 -= "yy"
println("删除的" + map3)
//拿取到map所有key
println("拿取到map所有key:" + map3.keys)
println("拿取到map所有key:" + map3.keySet)
//获取所有的value
println("获取所有的value:" + map3.values)
打印的值为:
修改的Map(lisi -> 40, zhangsan -> 50)
添加的Map(yy -> 22, lisi -> 40, zhangsan -> 50)
删除的Map(lisi -> 40, zhangsan -> 50)
拿取到map所有key:Set(lisi, zhangsan)
拿取到map所有key:Set(lisi, zhangsan)
获取所有的value:HashMap(40, 50)
(3)、遍历Map
val map3 = Map("zhangsan" -> 30, "lisi" -> 40)
//方法一。通过遍历key拿取到值
for (i <- map3.keys) println(i + "->" + map3(i))
//方法二,通过元组的方法拿取到值
for (i <- map3) println(i._1 + "->" + i._2)
//方法三
for((k, v) <- map3) println(k + " -> " + v)
lisi->40
zhangsan->30
lisi->40
zhangsan->30
lisi -> 40
zhangsan -> 30
10、Set集合
-
Set是代表没有重复元素的集合。
-
Set具备以下性质:
-
1、元素不重复
-
2、不保证插入顺序
-
-
scala中的set集合也分为两种,一种是不可变集合,另一种是可变集合。
不可变set集合
//创建一个空的不可变集
val/var 变量名 = Set[类型]()
//给定元素来创建一个不可变集
val/var 变量名 = Set[类型](元素1, 元素2, 元素3...)
def main(args: Array[String]): Unit =
val a = Set(1, 1, 2, 3, 4, 5)
println("a的长度大小"+a.size)
for(i<-a)println(i)
println("添加一个元素的新set:",a + 6)
println("删除一个元素的新set:",a -1)
println("删除多个元素的新set:",a -- Set(2,3) )
println("添加多个元素的新set:",a ++ Set(6,7,8) )
println("多个Set集合交集的新set:",a & Set(3,4,5,6))
println(a)
打印如下:
a的长度大小5
5
1
2
3
4
(添加一个元素的新set:,Set(5, 1, 6, 2, 3, 4))
(删除一个元素的新set:,Set(5, 2, 3, 4))
(删除多个元素的新set:,Set(5, 1, 4))
(添加多个元素的新set:,Set(5, 1, 6, 2, 7, 3, 8, 4))
(多个Set集合交集的新set:,Set(5, 3, 4))
Set(5, 1, 2, 3, 4)
注意:这里对不可变的set集合进行添加删除等操作,对于该集合来说是没有发生任何变化,这里是生成了新的集合,新的集合相比于原来的集合来说发生了变化
可变Set集合
要使用可变集,必须要手动导入:
import scala.collection.mutable.Set
11、列表 List
-
List是scala中最重要的、也是最常用的数据结构。
-
List具备以下性质:
-
1、可以保存重复的值
-
2、有先后顺序
-
-
在scala中,也有两种列表,一种是不可变列表、另一种是可变列表
-
不可变列表就是列表的元素、长度都是不可变的
-
语法
不可变列表
- 使用 List(元素1, 元素2, 元素3, ...) 来创建一个不可变列表,语法格式
val/var 变量名 = List(元素1, 元素2, 元素3...)
//使用 Nil 创建一个不可变的空列表
val/var 变量名 = Nil
//使用 :: 方法创建一个不可变列表
val/var 变量名 = 元素1 :: 元素2 :: Nil
def main(args: Array[String]): Unit =
val list1 = List(1, 2, 3, 4)
val list2 = Nil
val list3= 1::2::3::Nil
println(list1(0))
println(list3)
打印的值为
1
List(1, 2, 3)
可变列表
1、使用ListBuffer元素类型 创建空的可变列表,语法结构
val/var 变量名 = ListBuffer[Int]()
2、使用ListBuffer(元素1, 元素2, 元素3...)创建可变列表,语法结构
val/var 变量名 = ListBuffer(元素1,元素2,元素3...)
val a = ListBuffer[Int]()
val b = ListBuffer(1, 2, 3, 4)
println(b(0))
println("list数组首部:", b.head)
println("获取除了第一个元素外其他元素组成的列表", b.tail)
b += 5
println("添加应元素", b)
b ++= List(6, 7)
println("添加一个不可变列表", b)
b ++= ListBuffer(8, 9)
println("添加一个可变列表", b)
b -= 9
println("删除单个元素", b)
b --= List(7,8)
println("删除一个不可变的列表存在的元素", b)
b --= ListBuffer(5,6)
println("删除一个可变的列表存在的元素", b)
println("toList根据可变的列表生成一个不可变列表",b.toList)
println("toList根据可变的列表生成一个不可变列表,原列表不变",b)
println("toArray根据可变的列表生成一个新的不可变数组",b.toArray)
println("toArray根据可变的列表生成一个新的不可变数组,原列表不变",b)
打印如下
1
(list数组首部:,1)
(获取除了第一个元素外其他元素组成的列表,ListBuffer(2, 3, 4))
(添加应元素,ListBuffer(1, 2, 3, 4, 5))
(添加一个不可变列表,ListBuffer(1, 2, 3, 4, 5, 6, 7))
(添加一个可变列表,ListBuffer(1, 2, 3, 4, 5, 6, 7, 8, 9))
(删除单个元素,ListBuffer(1, 2, 3, 4, 5, 6, 7, 8))
(删除一个不可变的列表存在的元素,ListBuffer(1, 2, 3, 4, 5, 6))
(删除一个可变的列表存在的元素,ListBuffer(1, 2, 3, 4))
(toList根据可变的列表生成一个不可变列表,List(1, 2, 3, 4))
(toList根据可变的列表生成一个不可变列表,原列表不变,ListBuffer(1, 2, 3, 4))
(toArray根据可变的列表生成一个新的不可变数组,[I@3567135c)
(toArray根据可变的列表生成一个新的不可变数组,原列表不变,ListBuffer(1, 2, 3, 4))
12、函数式编程
-
我们将来使用Spark/Flink的大量业务代码都会使用到函数式编程。
-
下面的这些操作是学习的重点,先来感受下如何进行函数式编程以及它的强大
(1)、遍历 - foreach
方法描述
foreach(f: (A) ⇒ Unit): Unit
foreach | API | 说明 |
---|---|---|
参数 | f: (A) ⇒ Unit | 接收一个函数对象作为参数 函数的输入参数为集合的元素 返回值为空 |
返回值 | Unit | 空 |
def main(args: Array[String]): Unit =
val list = List(1, 2, 3, 4)
//定义一个匿名函数传入到foreach方法中
list.foreach((u: Int) => println(u))
//匿名函数的输入参数类型可以省略,由编译器自动推断
list.foreach(u => println(u))
// 当函数参数,只在函数体中出现一次,而且函数体没有嵌套调用时,可以使用下划线来简化函数定义
list.foreach(println(_))
//最简单直接
list.foreach(println)
(2)、映射 - map
-
集合的映射操作是将来在编写Spark/Flink用得最多的操作,是我们必须要掌握。
-
方法描述
def map[B](f: (A) ⇒ B): TraversableOnce[B]
-
方法说明
ap方法 | API | 说明 |
---|---|---|
泛型 | [B] | 指定map方法最终返回的集合泛型 |
参数 | f: (A) ⇒ B | 传入一个函数对象作为参数 该函数接收一个类型A(要转换的集合的元素类型) 返回值为类型B |
返回值 | TraversableOnce[B] | B类型的集合 |
val list = List(1, 2, 3, 4)
//定义一个匿名函数
val b=list.map((i:Int)=>i*10)
println(b)
//省略匿名函数参数类型
val c=list.map(i=>i*10)
println(c)
//最简单用下划线的方法
val d= list.map(_ * 10)
println(d)
打印结果如下
List(10, 20, 30, 40)
List(10, 20, 30, 40)
List(10, 20, 30, 40)
(3)、扁平化映射 - flatmap
-
映射扁平化也是将来用得非常多的操作,也是必须要掌握的。
-
方法描述
def flatMap[B](f: (A) ⇒ GenTraversableOnce[B]): TraversableOnce[B]
方法说明
flatmap方法 | API | 说明 |
---|---|---|
泛型 | [B] | 最终要转换的集合元素类型 |
参数 | f: (A) ⇒ GenTraversableOnce[B] | 传入一个函数对象作为参数 函数的参数是集合的元素 函数的返回值是一个集合 |
返回值 | TraversableOnce[B] | B类型的集合 |
def main(args: Array[String]): Unit =
val list = List("hadoop hive spark flink", "hbase spark")
val tt = list.flatMap(x => x.split(" "));
println(tt)
//简写
val t2 = list.flatMap(_.split(" "))
println(t2)
//flatMap该方法其本质是先进行了map 然后又调用了flatten
val t3 = list.map(_.split(" ")).flatten
println(t3)
打印结果如下
List(hadoop, hive, spark, flink, hbase, spark)
List(hadoop, hive, spark, flink, hbase, spark)
List(hadoop, hive, spark, flink, hbase, spark)
(4)、过滤 - filter
-
过滤符合一定条件的元素
-
方法描述
def filter(p: (A) ⇒ Boolean): TraversableOnce[A]
方法说明
filter方法 | API | 说明 |
---|---|---|
参数 | p: (A) ⇒ Boolean | 传入一个函数对象作为参数 函数的参数是集合中的元素 此函数返回布尔类型,满足条件返回true, 不满足返回false |
返回值 | TraversableOnce[A] | 列表 |
demo展示
def main(args: Array[String]): Unit =
val list = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
///过滤出集合中大于5的元素
val tt=list.filter(x=>x>5)
println(tt)
//把集合中大于5的元素取出来乘以10生成一个新的list集合
val t3=list.filter(x=>x>5).map(u=>u*10)
println(t3)
打印的值为:
List(6, 7, 8, 9, 10)
List(60, 70, 80, 90, 100)
(5)、排序 - sort
在scala集合中,可以使用以下几种方式来进行排序
-
sorted默认排序
-
sortBy指定字段排序
-
sortWith自定义排序
sorted默认排序
def main(args: Array[String]): Unit =
val list = List(5, 1, 2, 4, 3)
println(list.sorted)
List(1, 2, 3, 4, 5)
sortBy指定字段排序
def sortBy[B](f: (A) ⇒ B): List[A]
sortBy方法 | API | 说明 |
---|---|---|
泛型 | [B] | 按照什么类型来进行排序 |
参数 | f: (A) ⇒ B | 传入函数对象作为参数 函数接收一个集合类型的元素为参数 返回B类型的元素进行排序 |
返回值 | List[A] | 返回排序后的列表 |
结果如下:
val list2 = List("1 hadoop", "2 spark", "3 flink")
println(list2.sortBy(x=>x.split(" ")(0)))
打印的结果如下:
List(1 hadoop, 2 spark, 3 flink)
sortWith自定义排序
-
自定义排序,根据一个函数来进行自定义排序
-
方法描述
def sortWith(lt: (A, A) ⇒ Boolean): List[A]
sortWith方法 | API | 说明 |
---|---|---|
参数 | lt: (A, A) ⇒ Boolean | 传入一个比较大小的函数对象作为参数 函数接收两个集合类型的元素作为参数 返回两个元素大小,小于返回true,大于返回false |
返回值 | List[A] | 返回排序后的列表 |
val list3 = List(2, 3, 1, 6, 4, 5)
//降序
var tt = list3.sortWith((x, y) => x > y)
println(tt)
//升序
var tt2 = list3.sortWith((x, y) => x < y)
println(tt2)
//简写
var tt3 =list3.sortWith(_ > _)
println(tt3)
打印的结果:
List(6, 5, 4, 3, 2, 1)
List(1, 2, 3, 4, 5, 6)
List(6, 5, 4, 3, 2, 1)
(5)、聚合 - reduce
-
reduce表示将列表,传入一个函数进行聚合计算
-
方法描述
def reduce[A1 >: A](op: (A1, A1) ⇒ A1): A1
reduce方法 | API | 说明 |
---|---|---|
泛型 | [A1 >: A] | (下界)A1必须是集合元素类型的子类 |
参数 | op: (A1, A1) ⇒ A1 | 传入函数对象,用来不断进行聚合操作 第一个A1类型参数为:当前聚合后的变量 第二个A1类型参数为:当前要进行聚合的元素 |
返回值 | A1 | 列表最终聚合为一个元素 |
def main(args: Array[String]): Unit =
val a = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
//基础的写法
var b = a.reduce((x, y) => x + y)
println("基础的写法"+b)
//简单的写法
var c = a.reduce(_ + _)
println("简单的写法"+c)
//从左往右计算
var d = a.reduceLeft(_ + _)
println("从左往右计算"+d)
//从右往左计算
var f = a.reduceRight(_ + _)
println("从右往左计算"+f)
基础的写法55
简单的写法55
从左往右计算55
从右往左计算55
(6)、折叠 - fold
fold与reduce很像,但是多了一个指定初始值参数
def fold[A1 >: A](z: A1)(op: (A1, A1) ⇒ A1): A1
reduce方法 | API | 说明 |
---|---|---|
泛型 | [A1 >: A] | (下界)A1必须是集合元素类型的子类 |
参数1 | z: A1 | 初始值 |
参数2 | op: (A1, A1) ⇒ A1 | 传入函数对象,用来不断进行折叠操作 第一个A1类型参数为:当前折叠后的变量 第二个A1类型参数为:当前要进行折叠的元素 |
返回值 | A1 | 列表最终折叠为一个元素 |
def main(args: Array[String]): Unit =
val a = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
var e = a.fold(0)(_ + _)
println("简单折叠:",e)
var g = a.fold(5)(_ + _)
println("给定一个初始值,,折叠求和:"+g)
var h= a.foldLeft(10)(_ + _)
println("从左往右折叠:",h)
(简单折叠:,55)
给定一个初始值,,折叠求和:60
(从左往右折叠:,65)
13、高阶函数
使用函数值作为参数,或者返回值为函数值的“函数”和“方法”,均称之为“高阶函数”。
1、函数值作为参数
def main(args: Array[String]): Unit =
//定义一个数组
val array = Array(1, 2, 3, 4, 5)
//定义一个函数
val func = (x: Int) => x * 10
//函数作为参数传递到方法中
val tt= array.map(func)
println("通过map转化的新数组:",tt)
println("通过map转化的新数组最大:",tt.max)
打印的值为:
(通过map转化的新数组:,[I@17550481)
(通过map转化的新数组:,50)
2、匿名函数
一个没有名称的函数----匿名函数
def main(args: Array[String]): Unit =
val array = Array(1, 2, 3, 4, 5)
var a = array.map(x => x * 10)
println(a.max)
打印的值为:
50
3、柯里化
方法可以定义多个参数列表,当使用较少的参数列表调用多参数列表的方法时,会产生一个新的函数,该函数接收剩余的参数列表作为其参数。这被称为柯里化。
def main(args: Array[String]): Unit =
def getAddress(a: String): (String, String) => String =
(b: String,c: String) => a + "-" + b + "-" + c
var b=getAddress("china");
var c=b("beijing","tianAnMen")
println(c)
china-beijing-tianAnMen
4、闭包
函数里面引用外面类成员变量叫作闭包
def main(args: Array[String]): Unit =
var factor = 1
val f1 = (x: Int) => x * factor
println(f1(8))
factor=2
println(f1(8))
8
16
//定义的函数f1,它的返回值是依赖于不在函数作用域的一个变量
//后期必须要要获取到这个变量才能执行
//spark和flink程序的开发中大量的使用到函数,函数的返回值依赖的变量可能都需要进行大量的网络传输获取得到。这里就需要这些变量实现序列化进行网络传输。
def main(args: Array[String]): Unit =
def multiply(x: Double) = (y: Double) => x * y
//先进行科尔化
val doubleFunc = multiply(2)
val tripleFunc = multiply(3)
// 再对闭包进行计算
var u = doubleFunc(10)
var u2 = tripleFunc(10)
println(u)
println(u2)
20.0
30.0
14、scala面向对象编程之类
1、类的定义
scala是支持面向对象的,也有类和对象的概念。
-
定义一个Customer类,并添加成员变量/成员方法
-
添加一个main方法,并创建Customer类的对象,并给对象赋值,打印对象中的成员,调用成员方法
与java相比,他无需get set方法,就可以对变量进行赋值封装操作
import java.util.Date
class Customer
var name: String = _
var sex: String = _
val registerDate: Date = new Date
def sayHi(msg: String) =
println(msg)
object Main
def main(args: Array[String]): Unit =
val customer = new Customer
//给对象的成员变量赋值
customer.name = "张三"
customer.sex = "男"
println(s"姓名: $customer.name, 性别:$customer.sex, 注册时间: $customer.registerDate")
//对象调用方法
customer.sayHi("你好!")
打印的结果为:
姓名: 张三, 性别:男, 注册时间: Fri Apr 22 16:23:21 CST 2022
你好!
(1). var name:String = _, _表示使用默认值进行初始化
例如:String类型默认值是null,Int类型默认值是0,Boolean类型默认值是false...
(2). val变量不能使用_来进行初始化,因为val是不可变的,所以必须手动指定一个默认值
(3). main方法必须要放在一个scala的object(单例对象)中才能执行
2、类的构造器
主构造器
-
主构造器是指在类名的后面跟上一系列参数,例如
class 类名(var/val 参数名: 类型 = 默认值, var/val 参数名: 类型 = 默认值)
// 构造代码块
辅助构造器
-
在类中使用this来定义,例如
def this(参数名: 类型, 参数名: 类型) ...
package com.testScala.D_lei class Student(val name: String, val age: Int) val address: String = "beijing" // 定义一个参数的辅助构造器 def this(name: String) // 辅助构造器的第一行必须调用主构造器或其他辅助构造器或者super父类的构造器 this(name, 20) def this(age: Int) this("某某某", age) object test def main(args: Array[String]): Unit = val tt = new Student("张三"); println(s"name等于:$tt.name,address:$tt.address,age:$tt.age")
15、scala面向对象编程之对象
1、scala中的object
-
scala中是没有Java中的静态成员的。如果将来我们需要用到static变量、static方法,就要用到scala中的单例对象object
-
定义object
-
定义单例对象和定义类很像,就是把class换成object
-
-
演示
-
定义一个工具类,用来格式化日期时间
-
object DateUtils
// / 在object中定义的成员变量,相当于Java中定义一个静态变量
// 定义一个SimpleDateFormat日期时间格式化对象
val simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm")
// 构造代码
println("构造代码")
// 相当于Java中定义一个静态方法
def format(date: Date) = simpleDateFormat.format(date)
// main是一个静态方法,所以必须要写在object中
def main(args: Array[String]): Unit =
println DateUtils.format(new Date()) ;
(1). 使用object 单例对象名定义一个单例对象,可以用object作为工具类或者存放常量
(2). 在单例对象中定义的变量,类似于Java中的static成员变量
(3). 在单例对象中定义的方法,类似于Java中的static方法
(4). object单例对象的构造代码可以直接写在花括号中
(5). 调用单例对象的方法,直接使用单例对象名.方法名,访问单例对象的成员变量也是使用单例对象名.变量名
(6). 单例对象只能有一个无参的主构造器,不能添加其他参数
2、scala中的伴生对象
-
在==同一个scala文件,有一个class和object具有同样的名字==,那么就称这个object是class的伴生对象,class是object的伴生类;
-
伴生类和伴生对象的最大特点是,可以相互访问;
package com.testScala.E_duixiang
class Dog
val id = 1
private var name = "kkb"
def printName(): Unit =
//在Dog类中可以访问伴生对象Dog的私有属性
println(Dog.CONSTANT + name )
object Dog
//伴生对象中的私有属性
private val CONSTANT = "汪汪汪 : "
def main(args: Array[String])
val dog = new Dog
//访问私有的字段name
dog.name = "123"
dog.printName()
汪汪汪 : 123
(1). 伴生类和伴生对象的名字必须是一样的
(2). 伴生类和伴生对象需要在一个scala源文件中
(3). 伴生类和伴生对象可以互相访问private的属性
3、scala中object的apply方法
-
:==实现伴生对象Array的apply方法==
-
伴生对象的apply方法用来快速地创建一个伴生类的对象。
package com.testScala.E_duixiang
class Person(var name: String, var age: Int)
override def toString = s"Person($name, $age)"
object Person
// 实现apply方法
// 返回的是伴生类的对象
def apply(name: String, age: Int): Person = new Person(name, age)
// apply方法支持重载
def apply(name: String): Person = new Person(name, 20)
def apply(age: Int): Person = new Person("某某某", age)
def apply(): Person = new Person("某某某", 20)
object Main2
def main(args: Array[String]): Unit =
val p1 = Person("张三", 20)
val p2 = Person("李四")
val p3 = Person(100)
val p4 = Person()
println(p1)
println(p2)
println(p3)
println(p4)
Person(张三, 20)
Person(李四, 20)
Person(某某某, 100)
Person(某某某, 20)
(1). 当遇到类名(参数1, 参数2...)会自动调用伴生对象相应的apply方法,在apply方法中来创建对象
(2). 定义apply时,如果参数列表是空,也不能省略括号(),否则引用的是伴生对象
4、scala中object的main方法
-
scala和Java一样,如果要运行一个程序,必须有一个main方法。
-
而在Java中main方法是静态的,而在scala中没有静态方法。
object Main1
def main(args: Array[String]) =
println("hello, scala")
16、scala面向对象编程之继承
1、继承extends
-
scala和Java一样,使用extends关键字来实现继承。可以在子类中定义父类中没有的字段和方法,或者重写父类的方法。
-
package com.testScala.F_jicheng class Person1 var name = "jianghaojie" def getName = this.name class Student extends Person1 object main1 def main(args: Array[String]): Unit = val p1 = new Person1() val p2 = new Student() p2.name = "蒋皓洁" println(p1.getName) println(p2.getName)
jianghaojie 蒋皓洁
2、override和super
如果子类要覆盖父类中的一个非抽象方法,必须要使用override关键字
-
可以使用override关键字来重写一个val字段
-
可以使用super关键字来访问父类的成员
-
==示例1:class继承class==
class Person3
val name = "super"
def getName = name
class Student3 extends Person3
// 重写val字段
override val name: String = "child"
// 重写getName方法
override def getName: String = "hello, " + super.getName
object Main3
def main(args: Array[String]): Unit =
val p = new Student3();
println(p.name)
println(p.getName)
child
hello, child
3、isInstanceOf和asInstanceOf
-
我们经常要在代码中进行类型的判断和类型的转换。在Java中,我们可以使用instanceof关键字、以及(类型)object来实现,在scala中如何实现呢?
-
scala中对象提供==isInstanceOf==和==asInstanceOf==方法。
-
isInstanceOf判断对象是否为指定类的对象
-
asInstanceOf将对象转换为指定类型
-
Java | Scala | |
---|---|---|
判断对象是否是C类型 | obj instanceof C | obj.isInstanceof[C] |
将对象强转成C类型 | (C ) obj | obj.asInstanceof[C] |
获取类型为T的class对象 | C.class | classOf[C] |
-
==示例==
class Person4
class Student4 extends Person4
object Main4
def main(args: Array[String]): Unit =
val s1: Person4 = new Student4
// 判断s1是否为Student4类型
if(s1.isInstanceOf[Student4])
// 将s1转换为Student3类型
val s2 = s1.asInstanceOf[Student4]
println(s2)
com.test以上是关于Scala基础语法学习的主要内容,如果未能解决你的问题,请参考以下文章