Scala基础语法学习

Posted 捡黄金的少年

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Scala基础语法学习相关的知识,希望对你有一定的参考价值。

目录

一、变量

 二、数据类型

三、scala中的条件表达式

四、循环

五、while循环

六、方法

6、函数

7、数组

(1)、定长数组

(2)、变长数组

(3)、遍历数组

(4)、数组常用操作

8、元组 

9、映射Map

(1)、不可变map

(2)、可变Map

(3)、遍历Map

10、Set集合

11、列表 List

不可变列表

可变列表

12、函数式编程

(1)、遍历 - foreach

(2)、映射 - map

(3)、扁平化映射 - flatmap

(4)、过滤 - filter

(5)、排序 - sort

(5)、聚合 - reduce

(6)、折叠 - fold

13、高阶函数

1、函数值作为参数

2、匿名函数

3、柯里化

 4、闭包

14、scala面向对象编程之类

1、类的定义

2、类的构造器

15、scala面向对象编程之对象

1、scala中的object

2、scala中的伴生对象

3、scala中object的apply方法

4、scala中object的main方法

16、scala面向对象编程之继承

1、继承extends

2、override和super

 ​​​如果子类要覆盖父类中的一个非抽象方法,必须要使用override关键字

3、isInstanceOf和asInstanceOf

4、getClass和classOf

5、访问修饰符

6、调用父类的constructor

7、抽象类

17、scala面向对象编程之trait特质

1、作为接口使用

2、定义具体的方法

3、定义具体方法和抽象方法

4、定义具体字段和抽象字段

5、实例对象混入trait

18、模式匹配和样例类

1、匹配字符串

2、匹配类型

3、匹配数组

4、匹配集合

5、匹配元组

6、样例类

7、Option类型

8、偏函数

19、异常处理

1、 捕获异常

2、抛出异常

20、提取器(Extractor)

21、泛型

1、定义一个泛型方法

2、定义一个泛型类

22、上下界

23、协变、逆变、非变

24、隐式转换和隐式参数

1 隐式转换

.2 隐式参数

一、变量

val/var 变量名称:变量类型 = 初始值

注意:

  • val定义的是不可重新赋值的变量(值不可修改)

  • var定义的是可重新赋值的变量(值可以修改)

  • scala中声明变量是变量名称在前,变量类型在后,跟java是正好相反

  • scala的语句最后不需要添加分号、、

 惰性变量

  • Scala中使用==关键字lazy==来定义惰性变量,实现延迟加载(懒加载)。

  • 惰性变量只能是不可变变量,并且只有在调用惰性变量时,才会去实例化这个变量。

  • 语法格式

lazy val 变量名 = 表达式

 二、数据类型

基础类型类型说明
Byte8位带符号整数
Short16位带符号整数
Int32位带符号整数
Long64位带符号整数
Char16位无符号Unicode字符
StringChar类型的序列(字符串)
Float32位单精度浮点数
Double64位双精度浮点数
Booleantrue或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
foreachAPI说明
参数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) 、分组 - groupBy

  • 首先集合的元素得是kv对的;

  • 如果要将数据按照某值分组来进行统计分析,就需要使用到分组方法

  • groupBy表示按照函数将列表分成不同的组

  • 方法描述

def groupBy[K](f: (A) ⇒ K): Map[K, List[A]] 

  • 方法说明

groupBy方法API说明
泛型[K]分组字段的类型
参数f: (A) ⇒ K传入一个函数对象 接收集合元素类型的参数 返回一个K类型的key,这个key会用来进行分组,相同的key放在一组中
返回值Map[K, List[A]]返回一个映射,K为分组字段,List为这个分组字段对应的一组数据

scala> val a = List("张三"->"男", "李四"->"女", "王五"->"男")
a: List[(String, String)] = List((张三,男), (李四,女), (王五,男))

// 按照性别分组
scala> a.groupBy(_._2)
res0: scala.collection.immutable.Map[String,List[(String, String)]] = Map(男 -> List((张三,男), (王五,男)),
女 -> List((李四,女)))

// 将分组后的映射转换为性别/人数元组列表
scala> res0.map(x => x._1 -> x._2.size)
res3: scala.collection.immutable.Map[String,Int] = Map(男 -> 2, 女 -> 1)

//根据这个例子,思考下,作业中如何使用scala编程,实现词频统计?
 

//求每个省份有多少人?
val b = List("张三"->("男", "北京"), "李四"->("女", "河北"), "王五"->("男", "北京"))

scala> b.groupBy(_._2._2).map(x => (x._1, x._2.size))
res14: scala.collection.immutable.Map[String,Int] = Map(北京 -> 2, 河北 -> 1)

 

object yyy 
  def main(args: Array[String]): Unit = 
   val a = List("张三"->"男", "李四"->"女", "王五"->"男")
    println(a.groupBy(_._2))

    val list2 =List("a,b,c","y,c,a,e,a,c,a")
    var map=list2.flatMap(x=>x.split(",")).groupBy(x=>x).map(y=>(y._1,y._2.size));
    println(map)
    println("a的个数是:"+map("a"))
  

打印的值为 

Map(男 -> List((张三,男), (王五,男)), 女 -> List((李四,女)))
Map(e -> 1, y -> 1, a -> 4, b -> 1, c -> 3)
a的个数是:4

(6)、排序 - 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必须是集合元素类型的子类
参数1z: A1初始值
参数2op: (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