Scala学习笔记
- Scala笔记
-
- 一、学习Scala的目的
- 二、Scala的基本概念
-
- [2.1 JDK1.8版本的新特性](#2.1 JDK1.8版本的新特性)
- [2.2 Scala的运行机制](#2.2 Scala的运行机制)
- 三、Scala的基本语法
-
- [3.1 Scala中输出语句、键盘输入、注释语法](#3.1 Scala中输出语句、键盘输入、注释语法)
-
- [3.1.1 Scala注释三种,和Java一模一样的](#3.1.1 Scala注释三种,和Java一模一样的)
- [3.1.2 Scala键盘输入](#3.1.2 Scala键盘输入)
- [3.1.3 Scala输出](#3.1.3 Scala输出)
- [3.2 Scala变量和常量](#3.2 Scala变量和常量)
- [3.3 Scala中标识符](#3.3 Scala中标识符)
- [3.4 Scala中的数据类型](#3.4 Scala中的数据类型)
- [3.5 Scala中运算符](#3.5 Scala中运算符)
-
- [3.5.1 算术运算符](#3.5.1 算术运算符)
- [3.5.2 赋值运算符](#3.5.2 赋值运算符)
- [3.5.3 比较运算符](#3.5.3 比较运算符)
- [3.5.4 逻辑运算符](#3.5.4 逻辑运算符)
- [3.5.5 位运算符](#3.5.5 位运算符)
- [3.6 Scala中流程控制](#3.6 Scala中流程控制)
-
- [3.6.1 分支流程](#3.6.1 分支流程)
- [3.6.2 循环流程](#3.6.2 循环流程)
- 四、Scala的函数式编程
-
- [4.1 函数的基本语法](#4.1 函数的基本语法)
- [4.2 函数的形参列表问题](#4.2 函数的形参列表问题)
- [4.3 函数的返回值问题](#4.3 函数的返回值问题)
- [4.4 函数的高阶函数](#4.4 函数的高阶函数)
-
- [4.4.1 函数当变量使用:把函数重命名了](#4.4.1 函数当变量使用:把函数重命名了)
- [4.4.2 函数当参数来使用](#4.4.2 函数当参数来使用)
- [4.4.3 函数当作返回值来使用](#4.4.3 函数当作返回值来使用)
- [4.5 函数中匿名函数](#4.5 函数中匿名函数)
- [4.6 函数的高级使用](#4.6 函数的高级使用)
-
- [4.6.1 函数的闭包问题](#4.6.1 函数的闭包问题)
- [4.6.2 函数的柯里化](#4.6.2 函数的柯里化)
- [4.6.3 递归函数](#4.6.3 递归函数)
- [4.6.4 函数的惰性加载](#4.6.4 函数的惰性加载)
- [4.7 函数的简化操作](#4.7 函数的简化操作)
-
- [4.7.1 声明的简化](#4.7.1 声明的简化)
- [4.7.2 调用的简化:一般不建议使用,建议运算符的函数调用简化](#4.7.2 调用的简化:一般不建议使用,建议运算符的函数调用简化)
- [五、 Scala中面向对象](#五、 Scala中面向对象)
-
- [5.1 包和import导入](#5.1 包和import导入)
-
- [5.1.1 Scala包有两种管理代码的方式](#5.1.1 Scala包有两种管理代码的方式)
- [5.1.2 Scala中类的导入问题import](#5.1.2 Scala中类的导入问题import)
- [5.2 类的声明和类的组成](#5.2 类的声明和类的组成)
-
- [5.2.1 面向对象中的类](#5.2.1 面向对象中的类)
- [5.2.2 面向对象中类的属性](#5.2.2 面向对象中类的属性)
- [5.2.3 面向对象中类的方法](#5.2.3 面向对象中类的方法)
- [5.2.4 面向对象中类的代码块和内部类](#5.2.4 面向对象中类的代码块和内部类)
- [5.2.5 面向对象中类的构造器](#5.2.5 面向对象中类的构造器)
- [5.3 Scala中对象的创建](#5.3 Scala中对象的创建)
- [5.4 面向对象的特征](#5.4 面向对象的特征)
-
- [5.4.1 封装性](#5.4.1 封装性)
- [5.4.2 继承性](#5.4.2 继承性)
- [5.4.3 多态性](#5.4.3 多态性)
- [5.4.4 抽象性](#5.4.4 抽象性)
- [5.5 Scala中伴生对象Object](#5.5 Scala中伴生对象Object)
- [5.6 Scala中的case class样例类](#5.6 Scala中的case class样例类)
-
- [5.6.1 样例类的语法](#5.6.1 样例类的语法)
- [5.7 Scala中的特质Trait](#5.7 Scala中的特质Trait)
-
- [5.7.1 创建语法](#5.7.1 创建语法)
- [5.7.2 使用](#5.7.2 使用)
- 六、Scala中集合
-
- [6.1 Java集合体系](#6.1 Java集合体系)
-
- [6.1.1 Collection:单列集合](#6.1.1 Collection:单列集合)
- [6.1.2 Map:双列集合,key值不可重复,value可重复](#6.1.2 Map:双列集合,key值不可重复,value可重复)
- [6.2 Scala集合体系](#6.2 Scala集合体系)
-
- [6.2.1 不可变集合体系](#6.2.1 不可变集合体系)
- [6.2.2 可变集合体](#6.2.2 可变集合体)
- [6.3 Scala集合的使用](#6.3 Scala集合的使用)
-
- [6.3.1 Scala中数组-Seq的使用](#6.3.1 Scala中数组-Seq的使用)
- [6.3.2 Scala中List列表的使用](#6.3.2 Scala中List列表的使用)
- [6.3.3 Scala中Set集合的使用](#6.3.3 Scala中Set集合的使用)
- [6.3.4 Scala中元组Tuple](#6.3.4 Scala中元组Tuple)
- [6.3.5 Scala中Map集合的使用](#6.3.5 Scala中Map集合的使用)
- [6.4 Scala中集合的一些常用函数](#6.4 Scala中集合的一些常用函数)
-
- [6.4.1 基本函数](#6.4.1 基本函数)
- [6.4.2 集合的一些高级函数](#6.4.2 集合的一些高级函数)
- [6.4.3 集合的计算函数](#6.4.3 集合的计算函数)
- 七、Scala中的隐式转换
-
- [7.1 隐式转换函数](#7.1 隐式转换函数)
- [7.2 隐式转换参数](#7.2 隐式转换参数)
- [7.3 隐式转换类](#7.3 隐式转换类)
- 八、Scala中_的作用
Scala笔记
一、学习Scala的目的
Spark、Kafka等相关大数据技术框架底层都是由Scala编程语言编写的,Spark我们自己编写分布式程序时,Spark提供了多种编程语言风格,但是我们比较常用的是使用Scala编程。
二、Scala的基本概念
Scala是一门多范式编程语法,所谓多范式指的就是多种编程风格的语法,Scala主要是一门面向对象编程语言和函数式编程语言。
Scala的发明人是马丁奥德斯基,Scala语言2001年左右诞生的,融合了Java和JS中很多特性。
同时Java中很多特性也是从Scala语言中吸收到,JDK8.0版本拉姆达表达式就是从Scala中吸收到
2.1 JDK1.8版本的新特性
-
Java中函数编程式接口、拉姆达表达式、方法引用 接口的组成、时间日期类、Stream API、Optional类(解决NullPonitException的)
函数式接口:只有一个抽象方法的接口称之为函数式接口,一般情况函数式接口需要使用
@FunctionalInterface
-
Java中的拉姆达(λ)表达式是和Java中的一个接口紧密相关的,接口函数式编程接口(接口中只有一个抽象方法)
语法:(形参列表)-> {方法体;}
lambda表达式: 就等用于scala中匿名函数,使用函数式接口时,我们对函数式接口的简化操作,使用函数式接口大部分场景下都是使用匿名内部类的形式实现的,匿名内部类最核心的就是重写函数式接口的唯一的抽象方法把lambda就是简化匿名内部类的操作的
(形参列表) -> {方法体}
简化: 方法体只有一行 {} 可以省略;形参的类型可以省略的,如果形参只有一个那么 () 可以省略的javapackage lambda; import java.io.PrintStream; public class Demo { public static void test(Flyable flyable){ flyable.fly("zs"); } public static void test1(A a){ } /** * 使用函数式编程接口时,如果我们采用匿名内部类的形式,必须要去重写唯一的抽象方法,而且匿名内部类最核心的也是抽象方法 * 所以此时我们就是使用拉姆达表达式将匿名内部类的代码给简化了即可 * * (形参列表) -> {方法体} 就是抽象方法的简化 * @param args */ public static void main(String[] args) { test(System.out::println); test(name-> System.out.println(name)); } } interface A{ default void run(String name){} default int call(){return 0;} } package lambda; @FunctionalInterface public interface Flyable { void fly(String name); static int run(){ return 0;} }
拉姆达表达式的简化:
- 形参列表的类型可以省略的,因为拉姆达表达式对应的函数式编程接口的抽象方法是确定的
- 如果参数列表只有一个 那么形参列表的 () 可以省略的
- 如果方法体只有一行代码,而且这一行代码没有return关键字 ,那么方法体的 {} 可以省略,而且这一行代码不需要加分号
-
Java中的方法引用相当于是拉姆达表达式的升级版本,主要就是用来替换整个拉姆达表达式的,当拉姆达表达式的方法体是引用了另外一个类的方法,并且方法体中没有多余的代码时,可以使用方法引用来简化代码
方法引用:是为了进一步的简化我们的lambda表达式,只有当lambda表达式的方法体只有一行,而且这一行还是引用的其他类的方法完成的,而且一般方法无参的,有参也可以,那么lambda就可以使用方法引用简化:
对象名::方法名
类名::方法名
2.2 Scala的运行机制
- 编写
xxx.scala
源码文件,源码文件中可以使用Scala的SDK也可以使用Java的SDK - 使用scalac编译
xxx.scala
源码文件成为Java的二进制字节码文件xxx.class
- 使用scala命令将
xxx.class
加载到Java的JVM虚拟机当中运行的
三、Scala的基本语法
3.1 Scala中输出语句、键盘输入、注释语法
3.1.1 Scala注释三种,和Java一模一样的
3.1.2 Scala键盘输入
- 直接无缝衔接使用Java的键盘输入
Scanner
- 使用Scala提供的自带的键盘输入
StdIn.readxxx()
3.1.3 Scala输出
- 使用Java的输出语句
System.out.xxx
- 普通输出:
print()/println()
- 模板输出:
print/println(s"xxxxx$变量名")
- 占位符输出:
print/println("xxxxx%s %d",变量,变量)
3.2 Scala变量和常量
语法: var|val 变量名|常量名【:数据类型】 = 初始值;
【注意】虽然Scala中数据类型可以省略,但是Scala是一门强类型编程语法
3.3 Scala中标识符
- Scala的标识符由字母、数字、下划线、数学符号、$美元符号组成的,其中数字不能开头
- 如果标识符以数学符号开头,那么标识符中只能包含数学符号
- Scala标识符可以是关键字和保留字,但是关键字和保留字需要使用``包括
3.4 Scala中的数据类型
Scala是一门纯面向对象的编程语言,因此在Scala中所有的数据类型都是对象
Scala中所有类型的顶尖父类:Any,Any有两个直接子类:AnyVal、AnyRef
AnyVal是值类型:Byte、Short、Int、Long、Float、Double、Char、Boolean、Unit
AnyRef是引用类型:Java中所有类、Scala中所有类、Scala中所有集合、Null
Unit、Null、Nothing三个比较特殊的类型
3.5 Scala中运算符
3.5.1 算术运算符
没有++ --
3.5.2 赋值运算符
+= -=...
3.5.3 比较运算符
Scala中==代表比较值相等,比较地址相等用eq函数
3.5.4 逻辑运算符
3.5.5 位运算符
【注意】Scala运算符本质上是一个函数,函数的名字是数学符号,正常情况下运算符的使用语法应该如下: 1 + 1 1.+(1)
函数调用的时候可以简化:
- 函数调用的点可以省略的
- 如果函数的参数只有一个,那么 () 可以省略的
3.6 Scala中流程控制
顺序流程:代码遵循从上而下依次执行
3.6.1 分支流程
-
if类型的分支:Java一模一样的
-
模式匹配
-
语法:
scalax match{ case 值|x [模式守卫if] => case分支语句 case 值|x [模式守卫if] => case分支语句 case _ => case分支语句 }
-
【模式守卫】模式守卫可以做范围匹配,一般使用模式守卫时,case需要x
-
3.6.2 循环流程
-
for循环
-
until型的for循环:
for(i <- start until end)
-
to型的for循环:
for(i <- start to end)
-
增强的for循环------遍历集合或者数组:
for(elem <- 集合/数组的变量)
-
for循环的步长(迭代,默认情况下迭代+1):
for(i <- start until|to end by num)
-
循环守卫(满足某个条件再执行循环体):
for(i <- start until|to end 【by num】 if 语句)
-
多重循环:
for(i <- start until|to end by num 循环守卫 ;j<- start until|to end by num 循环守卫)
-
循环的返回值问题(将循环的值赋予给一个Scala集合):
var array = for(i <- start until|to end by num 循环守卫) yield i
-
-
while循环
-
do while循环
2~3:和Java语法是一模一样的
四、Scala的函数式编程
4.1 函数的基本语法
def 函数名(形参列表):函数的返回值类型={ 函数体 }
4.2 函数的形参列表问题
-
可变长形参 参数名:数据类型*
,一个函数只能有一个可变长形参,而且形参必须位于函数形参列表的末尾 -
形参的默认值,Scala函数当中,形参是可以赋予默认值的,一旦形参赋予默认值,那么调用参数的时候,带有默认值的形参就可以不用传递参数了,带有默认值的形参一般要求放到形参列表的最后,如果没有放到最后,那么调用的时候,给其他形参传递参数,需要带有参数名传递
def test(name:String=zs,age:int){}
test(age=1)--具名实参
4.3 函数的返回值问题
【注意】函数有两种特殊的返回值:Unit、Nothing
4.4 函数的高阶函数
【注】在Scala中,函数是一等公民,函数可以在Scala的任何位置充当任何的角色,函数可以声明在类中,也可以声明在函数中,还可以声明在参数列表中、还可以当作返回值,还可以当作一个变量
4.4.1 函数当变量使用:把函数重命名了
var d:函数的定义 = 函数名 _
【注意】函数的类型如何声明: (形参类型列表) => 返回值类型
示例:
函数的定义:
def test(a:Int,b:Int):Int={a+b}
函数的类型写法:
(Int,Int) => Int
4.4.2 函数当参数来使用
语法:
def test(a:Int,f:(Int,Int)=>Int):Unit={ }
4.4.3 函数当作返回值来使用
语法:
def test():(Int,Int)=>Int={ }
4.4.2~4.4.3 :Scala中存在匿名函数,专门使用在这两个场景
函数也是一种数据类型,函数类型的语法:
(形参类型列表) => 返回值类型
如果形参只有一个,那么 () 可以省略
4.5 函数中匿名函数
简化的前提:函数的类型必须是显示声明确定的
4.6 函数的高级使用
4.6.1 函数的闭包问题
函数闭包指的是将不属于本函数的变量或者对象也包含进来,直到该函数运行完成,外部变量或者对象才可以被释放。
var x:Int = 1 def test(a:Int):Int={ a*x }
4.6.2 函数的柯里化
将一个接受多个参数的函数给他转换成为一个接受单个参数的函数的过程
将一个接受多个参数的函数转换成为一个返回了函数的函数,返回的函数传递的值就是原先的第二个参数
其实闭包的一个使用场景
4.6.3 递归函数
-
函数内部调用本函数
-
递归三要素
- 递归入口:自己调用自己的的逻辑
- 递归出口:不能调用自己的逻辑
- 递归条件必须向出口迭代
4.6.4 函数的惰性加载
惰性加载指的是将函数的调用延迟到第一次使用函数的返回值的时候才会调用
使用语法: lazy val 变量名 = 函数名(实参)
此时函数的调用在第一次使用变量的时候才会调用 一旦惰性加载,变量名只能使用val修饰
4.7 函数的简化操作
4.7.1 声明的简化
-
如果函数没有参数,那么函数的括号可以省略
def test:Unit={}
-
函数的返回值可以省略的,可以根据函数体的最后一行自动推断,
【注意】如果函数体的最后一行使用return 关键字返回数据,那么函数的返回值一定不能省略 的
def test = { 1 }
-
函数体中,函数的返回值前的return关键字 可以省略的,自动根据最后一行推断函数的返回值
-
如果函数的返回值类型是Unit类型 那么**=号和函数**的返回值都可以省略
def test{}
-
匿名函数
- 定义:定义函数时,只关注函数的逻辑,不关注函数的名字,此时我们就可以使用匿名函数来定义函数:
(形参列表) => {函数体}
- 使用场景:当函数当作参数或者当作返回值使用的时候,可以使用匿名函数传递
- 简化
- 匿名函数的形参列表的类型可以省略的,因为当作参数或者返回值使用的时候,参数的类型定义死了
- 如果匿名函数的函数体只有一个,那么 {} 可以省略了
- 如果形参的参数名在函数体中只出现了一次,那么参数名就可以使用 _ 替代,同时形参列表可以省略了
- 定义:定义函数时,只关注函数的逻辑,不关注函数的名字,此时我们就可以使用匿名函数来定义函数:
4.7.2 调用的简化:一般不建议使用,建议运算符的函数调用简化
调用的语法 :对象名|类名.函数名(实参列表)
-
调用的点.可以省略的,
对象名|类名 函数名(实参列表)
-
如果实参列表为空,那么 () 可以省略,如果声明函数的时候没有加 () 那么调用的时候一定不能加 ()
-
如果函数的实参列表只有一个 那么 () 也可以省略
对象名|类名 函数名 唯一的实参
五、 Scala中面向对象
Scala源于Java中,因此在Scala中也存在面向对象编程思想,面向对象编程最核心的逻辑就是以类来组织代码,以对象来调用代码。Scala的面向对象和Java基本上思维是一致的,只不过就是语法稍微不一样而已。
5.1 包和import导入
包package:包是用来分类管理Scala代码的,将不同类型的代码放到不同的包下,便于我们管理
5.1.1 Scala包有两种管理代码的方式
-
采用和Java一样的管理机制,新建包,包下可以新建类和子包
-
采用包对象的管理机制,实现一个文件中存在多个包和多个scala类
5.1.2 Scala中类的导入问题import
在当前Scala类中,如果要使用非本包下的代码,那么我们就得需要通过import关键字导入才能使用。
-
每一个Scala类默认导入三个包
java.lang.
_scala._
scala.Predef._
-
Scala类中导入有一些规则和Java有点不一样
-
Scala可以在任何位置进行导包操作,代码只能在导包位置之后使用 我们可以把所有的包放到package之后 class之前
-
如果我们要导入一个包下的所有代码,那么可以使用_当作通配符使用
-
我们现在只想导入某一个包下的两个类,而非所有类
import xxxx.{x1,x2}
-
导包重命名操作:可以将一个类重命名为另外一个名字在当前类中使用
import xxxx.{x1=>x2}
x1类在当前类中可以使用x2名字来替代 -
屏蔽某一个包下的部分类:导入一个包下的所有代码,除了某几个类之外
import xxxx{x1=>_,x2}
导入xxxx包下的x2类,不导入x1这个类
-
5.2 类的声明和类的组成
5.2.1 面向对象中的类
- 类的定义
scala
访问控制修饰符 class ClassName 访问控制修饰符 (主构造器参数列表){
类体
}
【注意】在一个Scala文件可以存在多个类 多个类的访问控制修饰符没有要求的
- 访问控制符
三个 private protected public--不写
在同一个Scala文件中可以存在多个Scala类,权限没要求的
5.2.2 面向对象中类的属性
- 属性
属性用来描述类的特征
- 声明语法
访问控制修饰符 var|val 属性名:属性类型 = 值;
属性声明的时候必须加值,但是我不想给其他值,只想给默认值,那么值使用 _ 来代替(属性值可以填写 _ , _ 代表给属性赋予默认值,默认值看类型的)
【注意】
val修饰的属性 不能赋予 _ 默认值,必须给一个显示的值
属性前加一个注解
@BeanProperty
5.2.3 面向对象中类的方法
- 方法
Scala中方法就是函数,函数声明在类体中,称之为方法
- 语法
访问控制修饰符 def 方法名(形参列表):方法的返回值类型 ={ 方法体 }
5.2.4 面向对象中类的代码块和内部类
{} 类中类
5.2.5 面向对象中类的构造器
-
构造器是创建该类的实例对象的
-
Scala有两种构造器
-
主构造器:声明在类上的
class ClassName 访问控制修饰符 (形参列表)--主构造器
-
辅助构造器:声明在类中的构造器,语法:
def this(形参列表){ }
-
辅助构造器必须在首行直接或者间接的调用主构造器代码
【注意】
Scala中每一个辅助构造器必须直接或者间接的调用主构造器(显示声明调用)
主构造器因为没有构造器体,因此一般主构造器都是无参构造器,如果主构造器想给类中的属性赋值,那么我们需要把属性声明在主构造器的内部(构造器的形参既是类的属性还是构造参数)
主构造器的参数只要加上 var | val 那么就会变成类的属性
主构造器我们一般都是要求是无参构造器,而且主构造器一旦是无参的,那么主构造器的 () 可以省略
-
5.3 Scala中对象的创建
对象的创建就是变量|常量的定义
var|val 对象名:类 = new 类名(实参)
简化: 类型可以省略,自动推断;如果调用的构造器的实参为空,那么 () 也可以省略的
5.4 面向对象的特征
5.4.1 封装性
和Java的封装一样的概念,合理隐藏、合理暴露,控制类、属性、方法、构造器、内部类能被谁访问使用,不能被谁访问使用。
Scala的封装权限只有三种:private protected 不写(public)
封装性和Java的区别在于两个地方
- protected的权限比Java的权限更加严格:只有当前类和子类能访问,同包下的类都无法访问
- private的权限是私有化的,但是Scala开后门,private[包名] 只有当前类和指定包下能访问了 包一般是一个根包
5.4.2 继承性
和Java的概念是一样的,extends继承,Scala也是单继承,一旦继承父类,拥有父类中非私有化的属性和方法
5.4.3 多态性
定义变量的时候,分为编译时类型和运行时类型
向上转型:将儿子的对象给了父类的变量引用,可以直接给,不需要任何多余的操作
var s:Father = new Son()
向下转型:将父亲给儿子,不能直接给,需要使用asInstanceof[子类] 赋值,要求父亲的运行时类型必须是儿子或者儿子的子类类型
向下转型不是使用(子类)强转的,而是使用asInstanceof[子类]
函数
var s:Father = new Son()
var s1:Son = s.asInstanceof[Son]
如果我们要进行向下转型,最好先使用Scala提供的以下代码先判断父类的运行时类型是不是子类的类型
obj.isInstanceof[ClassName]
5.4.4 抽象性
- 抽象类
abstract class ClassName{ 抽象属性 抽象方法 }
- 抽象属性
没有 = 赋值的属性就是抽象属性
- 抽象方法
没有函数体的方法称为抽象方法
Scala中非抽象子类重写抽象类的属性和方法时,为了表示重写的概念,加了override关键字表示重写的过程
5.5 Scala中伴生对象Object
伴生对象是为了Scala和Java语言更好的集成,在Scala中不存在static关键字,但是Java中有静态的概念,Scala就推出了一个伴生对象,用来存放类似于静态的类内容
- Object定义的属性和方法就是当前Class类的静态内容,静态内容可以直接使用类名来调用
- Object类中存在一个功能特别强大的方法,apply方法
- apply方法 可以让我们创建对象的时候不需要使用new关键字,而是直接使用
类名(形参列表)
的形式构建类的对象 def apply(形参列表):Class ={ new ClassName(实参); }
- apply方法 可以让我们创建对象的时候不需要使用new关键字,而是直接使用
5.6 Scala中的case class样例类
样例类就等同于Java中JavaBean,同时Scala提供case class是为了丰富模式匹配的功能的
5.6.1 样例类的语法
case class(形参列表) extends Father......
case class ClassName(形参列表) extends F with T1
形参列表既是类的属性 还是类的主构造器,而且形参列表默认是使用private val 修饰符的 ,同时样例类自动给我们生成类的toString、hashCode、equals、apply方法
和模式匹配结合使用的
1、样例类的形参列表既是样例类的主构造器,还是样例类的属性,而且属性默认还是使用val修饰的2、样例类默认会给当前类生成
toString、hashCode、equals、Object伴生对象的apply方法
(参数和主构造器的参数保持一致的)3、如果想给样例类的属性生成getter和setter方法 ,只需要在每一个形参前加上一个
@BeanProperty
注解4、样例类可以应用于模式匹配中
5.7 Scala中的特质Trait
特质就是Java中的接口,只不过在Java中称之为接口,在Scala中称之为特质。Java中的所有接口都可以当作Scala的特质使用。
Scala中特质既可以包含抽象属性和抽象方法,还可以包含普通的属性和普通的方法。
5.7.1 创建语法
trait 特质名{ 抽象属性 抽象方法 普通的属性 普通的方法 }
5.7.2 使用
Scala中特质也是需要继承的,父类也是继承的 class Son extends Father with Trait1 with trait2
Scala中的特质不是用来实现的,而是用来继承的
class A extends F with T1 with T2.....
class A extends T1 with T2......
六、Scala中集合
Scala中可以使用Java的集合,但是Scala也给我们提供了一套集合体系,Spark Kafka既支持Scala集合体系,还支持Java集合集合
6.1 Java集合体系
6.1.1 Collection:单列集合
-
List:元素可重复、且元素加入有序、可以根据索引取值
- Vector
- ArrayList
- LinkedList
-
Set:元素不可重复、没有索引的概念
- HashSet:元素无序
- LinkedHashSet:元素加入有序
- TreeSet:元素是大小有序,需要用到比较器
6.1.2 Map:双列集合,key值不可重复,value可重复
- HashMap
- HashTable
- Properties
- LinkedHashMap
- TreeMap
6.2 Scala集合体系
6.2.1 不可变集合体系
每一次操作集合都是返回一个新的集合对象,而原有的集合不受任何的影响
scala.collection.immutable
- Set:不可重复
- Map:双列
- Seq:可以重复
6.2.2 可变集合体
每一次操作集合都是对原有的集合对象进行操作,而不是返回新的集合对象
scala.collection.mutable
- Set
- Map
- Seq
6.3 Scala集合的使用
6.3.1 Scala中数组-Seq的使用
- 不可变数组:Array
- 可变数组:ArrayBuffer
6.3.2 Scala中List列表的使用
- 不可变列表:List
- ::
- :::
- +:
- :+
- 可变列表:ListBuffer
6.3.3 Scala中Set集合的使用
元素无序不重复的
- 不可变Set集合:Set
1.+
2.- - 可变Set集合:Set
- +=
- -=
6.3.4 Scala中元组Tuple
【元组】不是集合
Scala比较特殊的一种容器,也可以存放一组数据,但是数据的类型可以不一样
元组最多能存放22个元素
元组的定义语法有两种: TupleN[xxx...] (xxx...)
获取元组的某一个元素,元组名._N
6.3.5 Scala中Map集合的使用
- 不可变Map
- 可变Map
6.4 Scala中集合的一些常用函数
6.4.1 基本函数
函数 |
---|
xxx.length |
xxx.size |
xxx.foreach(函数) |
xxx.mkString("分隔符") |
xxx.contains(xxxx) |
xxx.iterator |
6.4.2 集合的一些高级函数
- (1)获取集合的头 head()
- (2)获取集合的尾(不是头的就是尾) tail
- (3)集合最后一个数据
- (4)集合初始数据(不包含最后一个)
- (5)反转
- (6)取前(后)n 个元素
- (7)去掉前(后)n 个元素
- (8)并集
- (9)交集
- (10)差集
- (11)拉链
- (12)滑窗
6.4.3 集合的计算函数
- (1)sum求和
- (2)求乘积
- (3)最大值
- (4)最小值
- (5)排序
sorted(implicit ord: Ordering[B])
:根据当前集合中的元素进行大小比较 然后去排序,前提是集合中的元素必须是可以比较大小的,如果不能比较大小,那么需要传递一个比较器,比较器返回一个int类型的值sortedBy(f: xx=>xxx)((implicit ord: Ordering[xxx]))
:将集合中元素转换称为另外一种类型 然后根据转换的类型做比较sortWith(f:(xx,xx)=>Boolean)
: 自定义元素的比较规则,返回一个boolean类型的值
七、Scala中的隐式转换
扩展类的功能的,让原本两个毫无关系的类,也可以互相调用里面的方法,隐式转换的内容会自动触发
7.1 隐式转换函数
implicit def 函数名(类型):另外一个类型={ 如何创建另外一个类型 }
将输入类型转换称为输出类型,从而扩展某个类型的功能和方法
7.2 隐式转换参数
可以实现在调用参数的时候,哪怕参数没有默认值,也可以不用传递,也能调用函数
如果使用隐式转换参数,需要做两步操作
1、首先需要将函数的参数声明为隐式转换参数 implicit 变量名:数据类型
2、在函数调用的作用域当中,声明一个同类型的隐式变量,这样的话调用函数的时候,函数会从作用域当中去找一个同类型的参数自动填充 implicit 变量名:数据类型 = 值
【注意】在同一个作用域下,不能存在两个同类型的隐式变量
7.3 隐式转换类
八、Scala中_的作用
- _在模式匹配中,_代表的是未匹配到其他情况,默认情况
- 函数名 _ : _ 代表的是将函数当作一个整体来使用,而非调用函数
- 导包的时候_有两种用途_
- 导入一个包下的所有类
import java.lang.
- 屏蔽某一个包下的指定类
import java.util.{Arrays=>_}_
- 导入一个包下的所有类
- _声明属性的时候,属性值可以使用_替代:此时_代表给属性赋予默认值