导图社区 Scala
基于大数据spark框架下的scala语言,学习过程知识点整理,包含了scala的一些基础语法和函数、方法。
编辑于2021-01-22 20:49:02Scala 1
1 入门
概述
安装
2 变量和数据类型(重点)
笔记
语句结束不需要写 ; 号 如果一行写多个语句,那么这多个语句之间必须通过 ; 分割
数组、集合 数据装在()中,泛型用 [ ]
Scala中没有强转
main方法
只能创建在object中,在class中创建只是一个普通方法
public
scala中没有public关键字
默认就是类似 java public效果
static
scala中没有static关键字
class
scala class中的所有属性和方法都是类似java 非static修饰,所以在调用属性和方法的时候通过: 对象.属性/方法
object
scala object中的所有属性和方法都是类似java static修饰的,所以在调用属性和方法的时候通过: object名称.属性/方法
main方法格式(快捷键main)
def main(args: Array[String]): Unit
Unit相当于java的void,代表无返回值
但有实例对象 (),返回unit就是返回()
args参数名
Array[String]代表参数类型
Array就是代表数组,[String]代表数组中是存储的字符串类型的元素(泛型)
def是defined的缩写,def就是方法的标识
注释
scala注释和java完全一样
变量的命名规范
只能是数字、字母、下划线、$、特殊符号,首字母不能是数字
特殊符号是scala内部使用
命名采用驼峰原则
变量
格式
val/var 变量名:类型 = 值
val定义不能修改变量的值,赋值后不可修改
var定义可以修改变量的值
指的是地址值,scala中都是对象
scala中定义变量的时候必须初始化
可以省略变量类型,scala会自动推断变量类型
字符串输出
scala中得到字符串对象
1、双引号包裹
val/var s = "xx"
2、通过new的方式创建对象
new String("xx")
3、字符串拼接
1、通过+号拼接
"aa"+"bb"
2、通过插值表达式拼接
s"${外部变量1/表达式} , ${外部变量2}"
4、通过三引号的方式
val sql2 = s""" |select a.id,a.name,a.age | from ${table} a left join A b | on a.id = b.id | left join B c | on b.name=c.name """.stripMargin
"""...""" [能够完整的保留字符串格式]
尾部.stripMargin不可少
5、通过一些方法
subString/ format
val url = "http://hadoop102:8020/user/hive/warehouse/%s/%d" // %d // %f println(url.format("user_info",20))
键盘输入
从控制台读取数据
StdIn.readLine("XXX:")
从文件读取内容
Source.fromFile("文件路径","utf-8").getLines()
返回一个迭代器
getLines()获取文件所有行
数据类型关系
Any
AnyVal: 值类型
Int、Byte、Short、Long、Float、Double、Boolean、Char
StringOps
字符序列,可以使用foreach方法遍历字符串的每个字符, stringops是scala独有的,其中封装了Java和scala的一些方法
Unit
相当于java的void, 有一个实例 ()
AnyRef: 引用类型
String
引用了Java中的String
scala/java集合/数组
scala/java class
Null
所有 引用类型 的子类,有一个实例null,一般用来个变量 赋初始值,在给变量赋初始值的时候变量类型不能省略
不能用null给 值类型 赋初始值, 也不能赋初始值的时候不定义变量类型
Nothing
所有类型的子类。scala内部使用
可以把返回的值(异常)赋给其它的函数或者变量(兼容性)
所有类型的父类,类似java的object
数值类型间转换
数字与数字的转换
低精度向高精度转换[自动转换]
高精度转低精度[通过toXXX方法]
数字与字符串的转换
数字转字符串[通过插值表达式转换]
1、通过字符串拼接转换
数字 + ""
2、插值表达式转换
s"${数字}"
3、toString转换
数字.toString
4、valueOf方法
String.valueOf(数字)
字符串转数字[通过toXXX方法转换]
3 运算符(重点)
算术运算符
+ - * / %
比较运算符
== != >= <=
逻辑运算符
&& || !
赋值运算符
= += -= *= /
位运算符
& | << >> >>>
笔记
scala中方法的调用方式
1、对象.方法名(参数 , ..)
2、对象 方法名 (参数 , ..)
如果方法的参数只有一个,()可以省略
scala中操作符都是一个个的方法
6 面向对象
笔记
1 JSON与对象的互相转换
对象转json
JSON.toJSONString( 对象 , null . asInstanceOf [ Array [ SerializeFilter ] ])
json字符串转换对象
JSON.parseObject( json字符串 , classOf [所要转成的类名])
Scala包
基本语法
package 包名
package 包名 { .... }
创建子包,此种方式声明的包只能在target目录才能看到
三大作用
(1)区分相同名字的类
(2)当类很多时,可以很好的管理类
(3)控制访问范围
包的命名
不能用数字开头,也不要使用关键字
包说明
一个源文件中可以声明多个package
包对象
package object 包名{....}
其对应包下所有class和object的共享变量,可以被直接访问[子包除外]
导包说明
可以在任何地方导入包,但只能在当前作用域使用
1、导入包下所有类
import 包名._
2、导入包下某一个类
import 包名.类名
3、导入包下某几个类
导入包下某几个类: import 包名.{类名1,类名2,..}
4、导入包下某个类,并起别名
import 包名.{类名=>别名,..}
类和对象
定义类
基本语法
[修饰符] class 类名 { }
修饰符默认Public
属性
基本语法
[修饰符] [包名] var 属性名称 :类型 = 属性值
@BeanPropetry 修饰的属性,自动生成set/get方法
“ _ ”表示给属性一个默认值
var age: Int = _
通过“ _ ”赋予初始值必须定义变量类型
scala中属性有默认的set/get方法
get方法的方法名就是属性名
set方法的方法名就是 “属性名=”
方法
基本语法
同本文档描述
较object最前面多了 访问修饰符
创建对象
基本语法
val | var 对象名 [:类型] = new 类型()
没有参数、参数都有默认值 ()可省略
val修饰对象,不能改变对象的引用(即:内存地址),可以改变对象属性的值
var修饰对象,可以修改对象的引用和修改对象的属性值
构造器
主构造器
基本语法
class 类名 【访问修饰符】【val/var】 (类型:默认值) { }
定义在类名后面
主构造器中定义的参数其实就是属性
辅助构造器
基本语法
def this(形参列表) { }
定义在class里面
辅助构造器,函数的名称this,可以有多个,编译器通过参数的个数来区分
辅助构造方法不能直接构建对象,必须调用主构造方法调用
第一行必须要调用其他的辅助构造器或者是主构造器,scala会根据this()中传递参数的数量来区别各构造器
主构造器无参数,小括号可省略,对象时调用也可省略
如果构造器都有默认值可以省略()
构造器参数
未用任何修饰符修饰
是一个局部变量,在class内部使用
var修饰参数
可以修改
val修饰参数
不能修改
封装
@BeanProperty注解实现get和set方法
该注解不能用于private修饰的属性上
scala提供的@BeanProperty注解主要用来兼容java api
注解不能给val修饰的属性生成set方法
其余跟Java一致
继承
extends
scala中val修饰的属性子类也可以通过override关键字重写
var修饰的属性不能被重写,因为没必要
其余跟Java一致
抽象属性和抽象方法
基本语法
定义抽象类
abstract class 类名{ }
通过abstract关键字标记抽象类
定义抽象属性
val | var 属性名 : 类型
一个属性没有初始化,就是抽象属性
定义抽象方法
def 方法名( ) : 返回类型
只声明而没有实现的方法,就是抽象方法
定义抽象方法的时候方法的返回值类型必须定义,如果没有定义默认就是Unit
重写
override修饰重写
属性及方法都可重写
属性重写只支持val类型
匿名子类
跟Java一样
new 抽象类对象 重写抽象方法、属性
抽象类中可写
抽象属性/方法
具体属性/方法
单例对象
伴生类和伴生对象
作用:为了模拟Java的静态概念更好的交互
基本语法
scala中object就是单例对象 -- 所有方法、属性是类似静态的
伴生对象中定义apply方法之后,后续创建伴生类的对象(object)可以通过 object名称.apply(参数值,..) / object名称(参数值,..)
apply可省略
apply方法
笔记
1 apply方法可以重载
2 伴生对象和伴生类的构造器数量必须能对应的上
3 class与object要在同一个.scala源文件中
作用
1 伴生类和伴生对象可以互相访问对方的private修饰的属性和方法
2 用于简化伴生类对象的创建
定义
1 object声明一个类,class声明一个相同名字的类
2 定义在伴生对象中
语法
def apply(参数名:参数类型 , ...): 类名 = new 类名(参数名)
特质--接口(Trait)
声明
trait 特质名 { trait体 }
基本语法
没有父类
class 类名 extends 特质1 with 特质2 with 特质3 …
有父类
class 类名 extends 父类 with 特质1 with 特质2 with 特质3…
特质混入
创建对象时混入trait,而无需使类混入该trait
val t2 = new 类名 with trait类名
特质叠加
1 所with 的 trait有相名方法并且参数类表也一样,子类实现这些trait后会报错
解决办法: 重写这个相同的方法。如果还需调用父类的方法,那么可通过 super [父trait名] . 方法名 如果不指定父trait名字,默认最后一个with的trait方法
2 一个类(Sub)混入的两个trait(TraitA,TraitB)中具有相同的具体方法,且两个trait继承自相同的trait(TraitC)
将两个冲突的trait都表现出来
特质叠加执行顺序
extends优先于with叠加,后叠加的顺序在后面,相当于从右向左,与继承顺序相反
创建对象初始化时,则与继承顺序相同,从左向右
特质自身类型
this : 指定类型 =>
提醒子类在继承trait的时候必须先继承或者实现指定类型
扩展
类型检查和转换(重要)
scala中判断对象的类型
对象.isInstanceOf[类型]
scala中强转
对象.asInstanceOf[类型]
scala中获取对象的class形式
对象.getClass()
scala中获取类的class形式
classOf[类名]
枚举类和应用类
在object中写val修饰的变量即可
Type定义新类型
定义
给指定类型起别名
语法
type 别名 = 类名
5 函数式编程(重点)
笔记
方法就是函数,函数也是对象
原因是因为函数本质上是new了一个 FunctionN的函数,改函数重写了一个方法
用scala统计前N天的用户注册数
def getPaths(n:Int) = { //1、获取当前时间 val currentTime = LocalDateTime.now() //2、获取前n天的路径 for(i <- 1 to n) yield { //获取前i天的路径 val time = currentTime.plusDays(-i) val timestr = time.format(DateTimeFormatter.ofPattern("yyyyMMdd")) s"/user/hive/warehouse/user_info/${timestr}" } }
1、获取当前时间
2、获取前n天的路径
toBuffer
将调用该方法的集合转换为重写了tostring的集合
方法
基本语法
def 方法名( 参数名:类型,... ) : 返回值类型 = {方法体}
方法声明
无参
有返回值
无返回值
有参
有返回值
无返回值
方法参数
参数默认值
格式
def 方法名(参数名:参数类型=默认值,...) = { 方法体 }
带名参数
定义
在调用方法的时候指定将值传递给哪个参数
格式
方法名(参数名=值)
可变参数
格式
def 方法名(参数名: 参数类型*)
可变参数一般放置在最后
可变参数不能与默认值参数、带名参数(无意义)一起使用
传递数组到可变参数要用 -- 数组名:_*
默认值是在定义方法的时候使用, 带名参数是在调用方法时候使用, 可变参数两者都有
方法至简原则
1、如果使用块表达式的结果值作为方法的返回值,那么定义方法的时候,返回值类型可以省略
如果方法体中有return关键字,定义方法的时候必须定义返回值类型
2、如果方法体中只有一行语句, { } 可以省略
3、如果方法不需要参数,那么定义方法的时候 ( ) 可以省略
1 在定义方法的时候省略了(),在调用方法的时候也不能带上()
2 在定义方法的时候有(),在调用方法的时候()可有可无
4、如果方法不需要返回值,=可以省略 [=与{ }不能同时省略]
函数
基本语法
val 函数名【:(输入函数类型1.输入函数类型2)=>返回函数类型】 = (参数名:类型,...) => { 函数体 }
返回类型是自动定义的
函数声明
无参
有返回值
无返回值
有参
有返回值
无返回值
函数类型
(参数类型,参数类型,...) => 返回值类型
前两个泛型是函数参数类型,后一个泛型是函数的返回值类型
函数至简原则
数体中如果只有一行语句,{}可以省略
函数调用的时候不能省略 ( )
原因是因为函数本质上new了一个对象,不写()的话,打印的是一个对象类名
函数和方法的区别
1)方法定义在类中可以实现重载,函数不可以重载
原因是函数引用了一个对象,函数名相同的话,会有相同作用域
2)方法是保存在方法区,函数是保存在堆中
3)定义在方法中的方法可以称之为函数,不可以重载
4)方法可以转成函数, 转换语法: 方法名 _
高阶函数
定义
以函数作为参数或返回值的方法/函数称之为高阶函数
高阶函数的简化
1、方法传递参数的时候直接传递函数的表达式
2、函数的参数类型可以省略
3、如果函数的参数只有一个,那么()可以省略
4、如果函数的参数在函数体中只使用了一次,那么可以用_代替
1、如果函数的参数的使用顺序与定义顺序不一致,不能用_代替
2、如果函数的参数只有一个,并且在函数体中没有做任何操作直接将参数返回,此时不能用_简化
3、如果函数体中有()嵌套,此时参数又在()中以表达式的形式存在,此时不能用_简化
匿名函数
定义
没有函数名的函数
作用
一般是作为参数传给高阶函数
函数柯里化&闭包
柯里化
有多个参数列表的称之为柯里化
可将一个括号里的参数拆分为单个参数
闭包
函数体中使用了不属于自身(定义域外)变量的函数称之为闭包
递归
1、必须要有退出条件
2、递归必须定义返回值类型
控制抽象
定义
控制抽象是用在方法的参数中,是参数的形式存在
控制抽象其实就是一个块表达式
语法
=> 返回值类型
控制抽象在方法内调用的时候,不能带上( )
调用带有控制抽象的方法时,需要传一个块表达式
惰性求值
语法
lazy val 变量名 = 初始值
作用
等到变量真正使用的时候才会赋值
笔记
一般用于修饰较长的Sql语句
能节省内存
4 流程控制(重点)
块表达式
定义
由{ }包裹的代码段称之为块表达式
块表达式有返回值,返回值为{ }中最后一个表达式的结果值
后续除开for循环,while循环、do-while循环的{}外,其他的{}都可以看做块表达式
块表达式返回的结果如果是用Unit接收,那么对于方法来说没有结果值
if-else
单分支
双分支
多分支
笔记
scala中if-else用法与java的一样,但是scala的if-else有返回值,返回值就是符合条件的分支的{}中最后一个表达式的结果值
for循环
基本语法
格式
for( 变量 <- 集合/数组/表达式) {...}
守卫
for( 变量 <- 集合/数组/表达式 if (布尔表达式)) {...}
保护式为true则进入循环体内部,为false则跳过
嵌套循坏简写
for(变量1<- 集合/数组/表达式 ; 变量2<- 集合/数组/表达式;..)
to:
格式
start.to(end)/start to end
to方法会生成一个集合,此集合是一个左右闭合的集合
until:
格式
start.until(end)/start until end
until方法会生成一个集合,此集合是一个左闭右开的集合
yield表达式,
格式
for( 变量 <- 集合/数组/表达式) yield { 循环体 }
能够让for循环有返回值
while与do-while循环
scala中while循环与do-while的用法与java完全一样
Break和Continue
scala中没有break与continue
如何实现break?
1、return
2、抛异常的方式
scala实现break功能
1、导入包: import scala.util.control.Breaks._
2、通过breakable将整个循环包裹,在循环体中退出的时候使用break()方法退出 -- 在循坏体外包裹
scala实现continue功能
1、导入包: import scala.util.control.Breaks._
2、通过breakable将循环体包裹,在本次循环体中退出的时候使用break()方法退出 --在循坏体内包裹
Scala 2
8 模式匹配(重点)
语法
变量 match { //每个匹配条件后面的{}可以省略 case 条件 【if(布尔表达式)】 => {....} case 条件 【if(布尔表达式)】 => {...} ... //相当于switch的default case _ => ... }
1 返回值为符合条件的分支的{}最后一个表达式的结果值
2 条件中的变量名如果在=>右边不使用可以用 _ 代替
3 条件中的变量与外部变量无关系,如果要在条件中引用外部变量,变量名要大写
模式匹配类型
1 匹配所有的字面量
1 字符串
2 字符
3 数字
4 布尔值
casa 值 => ...
2 匹配类型
语法
case 变量名:类型 => ...
所有的集合都会进行泛型擦除,只有数组例外,会保留泛型,也就是说如果集合用匹配类型的方法匹配,那么无论第一个类型是什么都会匹配得上
3 匹配数组
语法
case Array(变量名1 [: 变量类型1] , 变量名2 [: 变量类型2] , _*) => ...
可以匹配元素个数, 也可以匹配元素个数和元素类型,还可匹配元素的确切值
4 匹配List
语法
case List(变量名1 [: 变量类型1] , 变量名2 [: 变量类型2] , _*) => ...
还可以匹配集合中的确切值,但是匹配的时候要按照顺序来
case (变量名1 [: 变量类型1]) :: (变量名2 [: 变量类型2]) :: List/Nil => ...
5 匹配元组(重要)
语法
case (元组本身)=> ...
case (变量名1,变量名2,...)=> ...
匹配元组的个数
case (变量名1:变量类型1,变量名2:变量类型2,....)=> ...
匹配元组的顺序和类型
匹配条件的元组的元素个数必须与元组个数一致
利用元组的模式匹配来获取多层嵌套的Key或Value
x match{ case (regionName1,(schoolName1,(className1,(stuName1,age1)))) =>println(stuName1) }
6 样例类(重要)
创建样例类语法
声明在object中
case class 类名([val/var] 属性名:类型,...)
val/var如果没写,默认是val修饰的
创建样例类对象语法
类名(值,...)
作用
用于封装数据
通类默认不能直接用于模式匹配,要想用于模式匹配需要在伴生对象中定义unapply方法,将对象解构成属性值
使用步骤 1
case class Region(regionName:String,school:School) case class School(schoolName:String,clazz:Clazz) case class Clazz(className:String,stu:Student) case class Student(name:String,age:Int) def main(args: Array[String]): Unit = { val list2 = List[Region]( Region("宝安区",School("宝安中学",Clazz("法师班",Student("安其拉",20)))), Region("宝安区",School("宝安中学",Clazz("法师班",Student("米拉迪",20)))), Region("宝安区",School("宝安中学",Clazz("法师班",Student("狄迪拉",20)))), Region("宝安区",School("宝安中学",Clazz("法师班",Student("佩恩",20)))) ) list2.foreach(x=>println(x.school.clazz.stu.name)) }
1 先创建样例类
2 在main 方法中创建集合,集合中再往样例类中封装数据
3 利用foreach循环从List中封装好的样例类中取数据
使用步骤 2
case class Person(val name:String,var age:Int,address:String) def main(args: Array[String]): Unit = { val person = Person("zhangsan",20,"shenzhen") person match{ case Person(x,y,z) => println(x) }
1 先创建样例类
2 在main方法中封装好数据
3 用模式匹配 --> case 样例类(传入属性个数多的变量)=> println(想打印的属性)
7 样例对象
样例对象
case object 名称
获取样例对象
object名称
作为枚举值使用
8 变量声明--模式匹配
语法
创建
普通数值
val /var (变量名1,变量名2,变量名3) = (变量值1,变量值2,变量值3)
数值 / 集合
val /var 数组/集合(变量名1,变量名2,变量名3) = 数组/集合(变量值1,变量值2,变量值3)
底层相当于: var 数组/集合名 = 数组/集合( 变量值1,变量值2... ) 数组/集合名 match{ case 数组/集合(变量名1,变量名2...) }
取值
普通数值
数值 / 集合
直接根据 变量名 就可以取值
底层用的模式匹配,变量名个数必须 = 变量值个数
9 for循环--模式匹配
for( 模式匹配 <- 集合/数组名 )
10 偏函数 -- 模式匹配 (重要)
定义
没有match关键字的模式匹配称之为偏函数
语法
val 函数名 : PartialFunction [IN,OUT] = { case 条件1 => ... case 条件2 =>.. ... } IN: 模式匹配参数类型 OUT: 模式匹配返回值类型
用法
需要匹配多次嵌套的元组时
一般用foreach ( func )
foreach 后跟代码块
list2.foreach({ case (regionName,(schoolName,(className,(name,age)))) =>println(name) }) ()中只有一个参数,()可省略
方法后面跟代码块,代码块中写 case
异常(重点)
捕获异常
try{..} catch{ case e:Exception => 异常返回值 } finally{...} [ 用于获取外部链接 ]
Try ( 代码 ).getOrElse( 默认值 )
抛出异常
throw new Excetion
scala没有throws关键字
隐式转换
隐式函数
定义
自动将一个类型装成另一个类型
语法
implicit def 方法名 (参数名: 待转换类型) : 目标类型 = {...}
使用时机
1、当前类型与目标类型不一致的时候,会自动调用隐式转换方法
2、对象使用了不属于自身的属性和方法/函数的时候,会自动调用隐式转换方法
隐式参数
定义
后续在调用方法的时候,某些参数scala会自动传入
语法
1 def 方法名(变量名:类型) (implict 参数名: 类型) = {..}
2、定义一个隐式参数 : implicit val 变量名: 类型 = 值
隐式类
定义
将一个类型[A]自动转成另一个类型[B]
语法
implicit class 类B ( 属性名 : 类A ) {...}
implicit class Dog(person:Person) { def add(x:Int,y:Int) = x+y } def main(args: Array[String]): Unit = { val p = new Person println(p.add(10, 20)) }
主构造器中的参数只能有一个属性 后续会自动将A--> B
隐式解析机制
1、首先会从当前作用域查找是否有符合要求的隐式转换
2、如果当前作用域没有符合要求的隐式转换,那么此时需要手动导入
1、如果隐式转换定义在object中,导入使用 import object名称._ / import object名称.隐式转换名称
2、如果隐式转换定义在class中,此时导入
1、创建class的一个对象: val 变量 = new class名称
2、import class名称._ / import class名称.隐式转换名称
3、如果object/class中能够找到多个符合条件的隐式转换,那么需要手动明确指定导入哪个隐式转换,不能使用 import object._的方式导入所有
泛型
协变和逆变和非变
逆变
定义
两个不同变量的泛型是父子关系 那么两个变量之间是颠倒泛型之间的父子关系
语法
-T
协变
定义
两个不同变量的泛型是父子关系 那么两个变量之间是继承泛型之间的父子关系
语法
+T
非变
定义
两个不同变量的泛型是父子关系 那么两个变量之间是没有任何关系
语法
T
泛型上下限
泛型上限
T <: 指定类型
指定类型或者是其子类
泛型下限
T>: 指定类型
指定类型或者是其父类
上下文限定
def 方法名[T:指定类型]() 等价于 def 方法名[T] () (implicit 参数名:指定类型[T])
7 集合(重要)
简介
笔记
1 集合类别
序列Seq
集Set
映射Map
都扩展自Iterable特质
不可变集合继承图
可变集合继承图
数组
笔记
添加/删除元素时 +/- 号含义
1 一个+/- 和两个+/-的区别
一个+/-
加/删除单个元素
两个+/-
添加/删除一个集合的所有元素
2 +与-的区别
+ 是添加元素
- 是删除元素
3 冒号在前与冒号在后以及不带冒号的区别
冒号在前是将元素添加到集合末尾
冒号在后是将元素添加到集合前面
不带冒号是将元素添加到集合末尾
4 带=与不带=的区别
带=是修改集合本身 【一般是可变集合拥有】
不带=是生成一个新集合,原有集合没有改变
不可变数组
创建
1、通过apply方法创建: Array[元素类型](初始元素,...) [常用]
2、通过new的方式创建: new Array[元素类型](数组的长度)
添加元素
++
++:
+:
:+
删除元素
没有删除命令
获取元素
通过角标获取元素的值
数组名(角标)
修改元素
通过角标的方式修改元素
数组名(角标) = 值
通过update方法
数组名.update(角标 , 要改的值)
遍历数组
查看数组
数组名 . mkString (",")
数组名.toBuffer
普通遍历
for (i <- 数组名 )
简化遍历
数组名 . foreach ( i => println ( i ) )
可变数组
创建
1、通过apply方法创建: ArrayBuffer[元素类型](初始元素,...) [常用]
2、通过new的方式创建: new ArrayBuffer[元素类型] ( )
添加元素
1 ++/++:/+:/:+/++=/++=:
2 追加数据
数组名.append(下标,要追加的数值)
3 向指定的位置插入数据
数组名.insert(下标,要插入的数值*)
删除元素
1 - / -=/ -- / --=
2 remove (下标)
获取元素
通过角标获取元素的值
数组名(角标)
修改元素
通过角标修改元素的值
数组名(角标) = 要修改的值
不可变数组与可变数组的转换
1 可变数组转不可变数组
数组名 . toArray
2 不可变数组转可变数组
数组名 . toBuffer
多维数组
Array . ofDim[类型](列的个数 , 行的个数)
Seq集合(List)
不可变List
创建
1、通过apply方法
List [元素类型] (初始元素 , ...)
2、通过 :: 方法创建
初始元素1 :: 初始元素2 :: List集合/Nil
Nil就是相当于是空List
使用Nil给变量赋予初始值的时候,变量的类型必须定义,而且变量类型只能List类型 如 var list4:List[Int] = Nil
添加元素
+ / :+ / :: / ++ / ++: / :::
:: 是添加单个元素 :::是添加一个结合所有元素
删除元素
无
获取元素
通过角标获取元素的值
数组名(角标)
修改元素
通过updated修改元素的值
数组名.updated(下标 , 修改值)
产生新的数组
可变ListBuffer
创建
ListBuffer[元素类型](初始元素,...)
添加元素
1 ++/++:/+:/:+/++=/++=:
2 追加数据
数组名.append(下标,要追加的数值)
3 向指定的位置插入数据
数组名.insert(下标,要插入的数值*)
删除元素
1 - / -=/ -- / --=
2 remove 方法
list.remove (下标)
list.remove (index , count)
从index开始删除count个元素
获取元素
与不可变List一样
修改元素
通过角标修改元素的值
数组名(角标) = 要修改的值
与不可变List一样
可变List转不可变List
list.toList
Set集合
不可变Set
创建
Set [元素类型] (初始元素)
添加元素
Set是无序的,添加元素没有顺序
1 ++/ ++: / +: / :+
删除元素
1 - / --
可变Set
创建
mutable . Set [元素类型] (初始元素)
添加元素
较不可变Set多了 = 号部分
set . add (新增值)
删除元素
较不可变Set多了 = 部分
较不可变Set多了 remove() 部分
更新元素
set.update(元素,true)
true为添加,false为删除
Map集合
不可变Map
* Option: Option代表当前有可能返回为空,提醒外部进行处理 get方法返回Option * Option有两个子类: Some、None * Some代表有值,不为空,值封装在Some对象中,后续可以通过get方法获取 * None代表没有值,为空.' * map取值采用getOrElse(key,默认值) 【如果key不存在就返回默认值】
创建
1、Map[K的类型,V的类型]( (K,V),(K,V),... )
2、Map[K的类型,V的类型]( K->V,K->V,..)
添加元素
1 ++/ ++: / +: / :+
2 Map . put ("Key" , value值)
删除元素
1 - / --
2 remove (K)
修改元素
map名 . updated ( "Key名" , 修改的值 )
生成新集合
获取value值
map名 . getOrElse ( "Key值" , 默认值 )
返回key的value值,如果没有返回默认值
获取所有key
map名 . keys
获取所有Value
map名 . values
可变Map
创建
1 mutable.Map[K的类型,V的类型]( (K,V),(K,V),... )
2 Map[K的类型,V的类型]( K->V,K->V,..)
添加元素
较不可变Map多了 = 号部分
删除元素
较不可变map多了 = 部分
获取value值
修改元素
map名 . update ( "Key名" , 修改的值 )
map名(“key”)= value值
map名 . put ( "Key名" , 修改的值 )
元组
封装简单数据
定义
1 存放各种相同或不同类型的数据
2 二元元组 --> 小括号内只有两个元素
3 scala中二元元组代表KV键值对
4 元组中最多只能存放22个元素
5 元素的个数和元素本身不能被修改
创建
1、通过 () 的方式创建
(初始元素 , ....)
2、二元元组
K -> V
元组的取值
元组名 . _ 角标
元组的角标从1开始
使用元组封装数据
val list = List[(String,Int,String)]( ("zhangsan",20,"shenzhen"), ("lisi",30,"beijing") )
集合常用函数
属性操作函数
length
集合长度
size
集合大小
foreach
遍历
针对集合每个元素进行操作
集合 . foreach ( println (_) )
没有返回值
iterator
迭代器
mkString ( )
生成字符串
contains ( 元素 )
是否包含
isEmpty
判断集合是否为空
衍生集合
distinct
去重
drop( N )
删除前N个元素,保留剩余的元素
dropRight( N )
删除后N个元素,保留剩余的元素
head
获取第一个元素
tail
获取除开第一个元素的所有元素
init
获取除开最后一个元素的所有元素
last
获取最后一个元素
reverse
反转
slice( n , k )
获取n->k的子集合
sliding( 窗口长度 , 滑动长度 )
滑窗函数:以窗口长度取值,再移动滑动长度
take( n )
获取前n个元素
takeRight( n )
获取后n个元素
集合1 .union 集合2
并集【将两个集合合并,不会去重】
集合A .diff 集合B
差集【A差B的结果就是取出A中有B中没有的元素】
集合1 .intersect 集合2
交集
集合1. zip ( 集合2 )
拉链
集合 . unzip
返回一个元组
反拉链
集合计算函数(初级)
集合 . max
获取最大值
集合 . min
获取最小值
集合 . sum
求和
集合 . sorted
直接根据元素本身排序,默认升序
集合 . maxBy ( func :集合元素类型 => B)
根据指定字段(func指定)获取最大值
集合 . minBy ( func:集合元素类型 => B )
根据指定字段(func指定)获取最小值
集合 . sortBy ( func:集合元素类型 => B )
//自己指定比较规则 implicit val ordering = new Ordering[Int]{ override def compare(x: Int, y: Int): Int = { if(x>y) -1 else if(x==y) 0 else 1 } }
可按自己指定规则比较, 需要 new Ordering[类型]重写compare方法, 需要在变量前加上implicit 原因是 sortBy内部柯里化了 Ordering方法
根据指定的字段 (func函数指定) 排序,默认升序
集合 . sortWith ( x , y )
第一个参数x<第二个参数y,升序 第一个参数x>第二个参数y,降序
都是传进一个字段
控制集合排序后的升降序的几种方法
1 reverse
2 用sortBy, 并创建Ordering匿名对象,重写chompare方法
3 用sortWith方法自己定义
集合计算函数(高级)
map( func: 集合元素类型 => B )
转化/映射(传入一个对集合中单个元素的处理办法)
1 主要用于类型/格式的转换
2 map会生成一个新集合,新集合的长度 = 原集合长度
3 针对一对一的场景(传入一个值,输出一个值)
flatten
压平
flatten是将第二层集合去掉
用于一对多场景,将集合炸开
flatMap(func: 集合元素类型 => 集合 )
map + flatten (传入一个对集合中单个元素的处理办法)
1 较flatten来说多了数据处理
2 一对多场景
3 执行顺序是先Map再flatter, Map的结果一定是一个多层的集合
filter ( func : 集合元素类型 => Boolean)
过滤(传入过滤判断语句)
1 保留函数返回值为true的数据
2 func方法传一个集合中的数据,并依据方法体计算是否过滤
groupBy ( func : 集合元素类型 => K )
分组(传入指定分组字段)
1 是针对集合每个元素操作
2 结果是Map,Map的key是指定分组的key,map的value值是key所在原集合的所有元素
Map(北京 -> List((lisi,15,北京)), 深圳 -> List((zhangsan,20,深圳), (wangwu,30,深圳)))
3 多变一(将多行数据【元组】转换为一行Map【KV键值对】)
reduce(func: (集合元素类型,集合元素类型)=> 集合元素类型 )
聚合(传入两个变量 => 变量处理方法体)
1 第一个参数是上一次的聚合结果,第二参数是当前要聚合的元素
2 第一个参数在第一次计算的时候,初始值 = 集合第一个元素
reduceRight(func: (集合元素类型,集合元素类型)=> 集合元素类型 )
聚合(从右至左)
1 第二个参数是上一次的聚合结果,第一个参数是当前要聚合的元素
2 第二个参数在第一次计算的时候,初始值 = 集合最后一个元素
fold (第一次计算的时候的初始值) (func: (集合元素类型,集合元素类型)=> 集合元素类型 )
折叠
fold与reduce的区别在于有初始值
foldRight(第一次计算的时候的初始值) (func: (集合元素类型,集合元素类型)=> 集合元素类型 )
折叠(从右至左)