scala总结
一、简介
java中main方法: public static void main(String[] args){...}
- scala中没有static关键字
- class: 里面的所有的属性与方法都是非static的
- object: 里面的所有的属性和方法都是类似java static修饰的。
object WordCount {
val name:String = "zhangsan"
/**
* scala中没有public修饰符,默认就是public效果
* def: defined的缩写,def标识方法
* main: 方法名
* Array[String]: Array代表是数组,[]是泛型使用,[]里面的类型代表当前Array中转载的元素类型
* Unit: 相当于java 的void
*
* scala中如果一行只写一个语句,那么;可以省略
* 如果一行写多个语句,;用来分割这多个语句
*/
def main(args: Array[String]): Unit = {
//java语法
System.out.println("wordcount")
//scala
println("wordcount")
println(WordCount.name)
}
}
第 1 章 Scala变量和数据类型
1.java注释:
- 单行注释: //
多行注释: /.../
文档注释: /*../
scala的注释与java完全一样
*/
2.定义变量
/**
* java中变量定义: 类型 变量名 = 值
*
*
*
* scala中变量定义语法: val/var 变量名:变量类型 = 值
* val与var的区别:
* val定义的变量不可以被重新赋值
* var定义的变量可以被重新赋值
* scala在定义变量的时候,变量类型是可以省略,省略之后scala会自动推断数据类型
*
* scala定义变量的时候必须初始化
* @param args
*/
def main(args: Array[String]): Unit = {
val name:String = "zhangsan"
//val定义的变量不可以被重新赋值
//name = "lisi"
var age:Int = 100
age = 200
println(name)
println(age)
val address = "shenzhen"
println(address)
}
}
3.控制台输入
/**
* scala中读取控制台输入的数据: StdIn
*
* 读取文件内容: Source.fromFile(path,"utf-8")
*/
def main(args: Array[String]): Unit = {
val str = StdIn.readLine("请输入一句话")
println(str)
println(Source.fromFile("d:/data.txt", "utf-8").getLines().toBuffer)
}
4.数据类型
/**
* java数据类型:
* 1、基本数据类型
* byte、short、char、int、long、float、double、boolean
* 2、引用数据类型
* String、class、集合、数组
*
* scala数据类型:
* Any: 是所有类的父类
* AnyVal: 值类型
* Byte、Short、Char、Int、Long、Float、Double、Boolean
* Unit: 相当于java的void, 有一个实例()
* StringOps: 对java String的扩展
* AnyRef: 引用类型
* String、scala class、java class、scala集合、java集合,..
* Null: 是所有引用类型的子类, 有一个实例null[null一般是给引用类型赋初始值使用,在定义变量的时候如果使用null赋初始值,此时变量的类型必须定义]
*
* Nothing: 所有类型的子类,但是不是给程序员使用,是scala内部使用
*
* @param args
*/
def main(args: Array[String]): Unit = {
/**
* String str = null
* str = "zhangsan"
*
* class Person
*
* class Student extends Person
*
* Student s = new Student
*
* s = new Person
*/
var s:String = null
s = "zhangsan"
println(s)
//val a:Int = null
//println(a)
}
5.获取字符串
/**
* java中如何得到一个字符串:
* 1、通过""包裹
* 2、new String(..)
* 3、通过一些方法
* 4、字符串拼接【+】
* scala中得到一个字符串:
* 1、通过""包裹
* 2、字符串拼接[插值表达式] s"${变量名/表达式}"
* 3、new String(..)
* 4、通过""" """包裹[能够保留字符串的输入的格式]
* 5、通过一些方法
* @param args
*/
def main(args: Array[String]): Unit = {
//1、通过""包裹
val name = "ZHANGSAN"
val address = "shenzhen"
val str = name + address
//2、字符串拼接
val str2= s"${name}-${address}"
println(str2)
val str3 = s"1+1=${1+1}"
println(str3)
val str5 = new String("hello")
println(str5)
//3、通过三引号包裹
val sql =
"""
|create table student(
| id string,
| name string,
| age string)COLUMN_ENCODED_BYTES=0
""".stripMargin
println(sql)
//三引号与插值表达式结合使用
val tableName = "student"
val sql2 =
s"""
|create table ${tableName}(
| id string,
| name string,
| age string)COLUMN_ENCODED_BYTES=0
""".stripMargin
println(sql2)
println(str2.substring(2))
val str6 = "hello %s".format("lisi")
println("http://www.xx.com/aa/bb?ip=%s".format("192.168.1.102"))
println("http://www.xx.com/aa/bb?ip=%d".format(10))
println(str6)
}
6 .类型的转换
/**
* 数字和数字的转换
* 1、低精度向高精度转换: Int->Long
* java中: 自动转换
* scala中: 自动转换
* 2、高精度转低精度: Long->Int
* java中: 强转
* scala: toXXX方法
* 数字和字符串的转换
* 1、数字转字符串
* java: 字符串拼接
* scala: 字符串拼接\toString
* 2、字符串转数字
* java: Integer.ValueOf(字符串),..
* scala: toXXX方法
*/
def main(args: Array[String]): Unit = {
//低精度向高精度转换
val a:Int = 10
val b:Long = a
//高精度转低精度
val c:Long = 100
val d:Int = c.toInt
println(d)
//数字转字符串
val s:String = c.toString
val s1:String = s"${c}"
println(s)
println(s1)
//字符串转数字
val s2 = "10"
val e:Int = s2.toInt
println(e)
//字符串中.不一定是小数点
val s3 = "10.0"
//val f:Int = s3.toInt
//println(f)
val g:Double = s3.toDouble
println(g)
}
第 2 章 Scala中运算符和流程控制
1.运算符
/**
* java中运算符:
* 1、算数运算符: +、-、*、/、% ++ --
* 2、比较运算符: > < >= <= != ==
* 3、逻辑运算符: && || !
* 4、赋值运算符: = += -= *= /=
* 5、位运算符: < > & | >>
* 6、三元运算符: 逻辑表达式? 表达式1: 表达式2
*
* scala中没有三元运算符,如果想要实现三元运算符可以通过if-else做
* scala没有++、--运算符。
* scala中运算符:
* 1、算数运算符: +、-、*、/、%
* 2、比较运算符: > < >= <= != ==
* 3、逻辑运算符: && || !
* 4、赋值运算符: = += -= *= /=
* 5、位运算符: < > & | >>
*
* scala中运算符都是方法。
*/
def main(args: Array[String]): Unit = {
val a = 10
val c = a + 20
val d = a.+(20)
println(d)
}
2.块表达式
/**
* 块表达式: 由{ }包裹的一块代码称之为块表达式
* 块表达式有返回值,返回值是{ }中最后一个表达式的结果值
* 后续大家看到{ }就可以认为是块表达式[ for循环、while循环的大括号不能看做块表达式]
*
*/
def main(args: Array[String]): Unit = {
val b = {
println("hello....")
val c = 10+10
//return "xx"
}
println(b)
println("----------------------")
10
//return "xx"
}
3.条件表达式
/**
* java中条件表达式的用法:
* 1、单分支: if
* 2、双分支: if-else
* 3、多分支: if-else if -..-else
*
* scala中条件表达式的用法:
* 1、单分支: if
* 2、双分支: if-else
* 3、多分支: if-else if -..-else
* scala的条件表达式有返回值,返回值是符合条件的分支的{ }的最后一个表达式的结果值
*/
def main(args: Array[String]): Unit = {
val a =10
//单分支
if(a%2==0){
println("a是偶数")
}
//双分支
if(a%3==0){
println("a是3的倍数")
}else{
println("a不是3的倍数")
}
//多分支
if(a%3==0){
println("a是3的倍数")
}else if(a%4==0){
println("a是4的倍数")
}else{
println("其他...")
}
//if表达式有返回值
val b = if(a%2==0){
println("..............")
a*a
}
println(b)
val c = if(a%10==0){
if(a%5==0){
println("5.。。。。。。。。")
a*a
}else{
println("+++++++++++++")
a+10
}
}
println(c)
}
4.for循环
/**
* java的for循环:
* 1、基本for: for(int i=0;i<=100;i++)
* 2、增强for: for(类型 变量: 集合/数组)
*
* scala中重要的两个方法:
* to:
* 用法: startIndex.to(endIndex)
* 结果: 会生成一个左右闭合的集合
* until:
* 用法: startIndex.until(endIndex)
* 结果: 会生成一个左闭右开的集合
* scala中方法调用有两种方式:
* 1、对象.方法名(参数值,..)
* 2、对象 方法名 (参数值,..) [如果方法只有一个参数,此时()可以省略]
* scala for循环语法: for(变量 <- 数组/集合/表达式) { 循环体 }
* for循环的守卫: for(变量 <- 数组/集合/表达式 if(布尔表达式)) { 循环体 }
* 步长: for(变量 <- start to end by step) { 循环体 }
* 嵌套for循环: for(变量 <- 数组/集合/表达式;变量 <- 数组/集合/表达式;...) { 循环体 }
* 变量嵌入: for(变量 <- 数组/集合/表达式; 变量2 = 值 ;变量 <- 1 to 变量2;...)
* for默认是没有返回值的,如果想要for有返回值需要用yield表达式: for(变量 <- 数组/集合/表达式) yield { 循环体 }
*
* @param args
*/
def main(args: Array[String]): Unit = {
//基本用法
for( i <- 1 to 10){
println(s"i=${i}")
}
println("+"*100)
//步长
for( j<- (1 to 10).by(2) ){
println(s"j=${j}")
}
println("-"*100)
for( j<- 1 to 10 by 2 ){
println(s"j=${j}")
}
println("*"*100)
for(k<- 1 to 10){
if(k%2==0){
println(s"k=${k}")
}
}
println("*"*100)
//守卫
for(k<- 1 to 10 if(k%2==0)) {
println(s"k=${k}")
}
/**
* for(k<- 1 to 10){
* println(s"k=${k}")
* if(k%2==0){
* println(s"k=${k}")
* }
* }
* 此循环不能通过守卫简化,因为if语句之前还有其他的语句
*/
println("*"*100)
for(i<- 1 to 10){
for(j<- i to 10){
println(s"i+j=${i+j}")
}
}
//通过scala嵌套for循环简化上面循环
println("*"*100)
for(i<- 1 to 10; j<- i to 10){
println(s"i+j=${i+j}")
}
/* for(i<- 1 to 10){
println(s"i=${i}")
for(j<- i to 10){
println(s"i+j=${i+j}")
}
}
不能使用scala嵌套for循环简化
*/
for(i<- 1 to 10 ){
if(i%2==0){
for(j<- i to 10){
println(s"i+j=${i+j}")
}
}
}
for(i<- 1 to 10 if (i%2==0); j<- i to 10 ){
println(s"i+j=${i+j}")
}
println("*"*100)
for(i<- 1 to 10){
val k = i * i
for(j<- 1 to k){
println(s"i+j=${i+j}")
}
}
println("*"*100)
//变量嵌入简化
for(i<- 1 to 10; k= i*i;j<- 1 to k){
println(s"i+j=${i+j}")
}
//yield表达式
val result = for(i<- 1 to 10) yield {
i * i
}
println(result.toBuffer)
println("------------------")
1 to 10 foreach(println(_))
}
5.while和do-while
/**
- scala中while、do-while的用法与java一样
- while与do-while的区别:
- while 先判断在执行
- do-while 先执行在判断
- @param args
*/
def main(args: Array[String]): Unit = {
var i = 11
while ( i<=10 ){
println(s"i=${i}")
i=i+1
}
println("*"*30)
var j =11
do{
println(s"j=${j}")
j = j+1
}while(j<=10)
}
6.循环控制break
/**
* java中使用break与continue控制循环
* break: 结束整个循环
* continue: 结束本次循环立即开始下一次循环
*
* scala中没有break与continue
* 实现break:
* 1、导入包:
* 2、使用breakable以及break方法
* @param args
*/
def main(args: Array[String]): Unit = {
//break
var i=0
/*while (i<=10){
if(i==5){
throw new Exception("......")
}else{
println(s"i=${i}")
i=i+1
}
}*/
//scala封装的break实现
breakable({
while (i<=10){
if(i==5) break()
println(s"i=${i}")
i=i+1
}
})
//continue
var j=0
/* while (j<=10){
try{
if(j==5){
j=j+1
throw new Exception("...")
}
println(s"j=${j}")
j=j+1
}catch {
case e:Exception =>
}
}*/
//使用scala的封装实现continue
while (j<=10){
breakable({
j=j+1
if(j==5) break()
println(s"j=${j}")
})
}
}
第 3 章 Scala中方法和函数
1.Scala中方法定义
/**
* 方法语法: def 方法名( 变量名:类型,... ) : 返回值类型 = { 方法体 }
*
* scala方法可以定义在方法中
*
* 方法如果定义在类中是可以重载的
*
* 方法如果定义在方法中是不可以重载的
*/
def main(args: Array[String]): Unit = {
val result = add(2,3)
println(result)
//scala方法可以定义在方法中
def add2( x:Int,y:Int ) = { x* y }
//def add2( x:Int ) = { x* 10 }
println(add2(4, 5))
}
//方法如果定义在类中是可以重载的
def add( x:Int , y:Int ) = {
x + y
}
def add( x:Int ) = {
x * 10
}
1.2.Scala方法简化
/**
* scala方法的简化原则:
* 1、如果方法体中只有一行语句,{ }可以省略
* 2、如果方法不需要返回值,那么=可以省略
* 3、如果使用方法体{}中最后一个表达式的结果值作为方法的返回值,那么此时返回值类型可以省略
* 如果方法体中有return关键字必须定义返回值类型
* 4、如果方法不需要参数,那么定义方法的()可以省略
* 如果定义方法的时候没有(),那么在调用方法的时候也不能带上()
* 如果定义方法的时候有(),那么在调用方法的时候()可以省略也可以不省略
* 在简化的时候,=与{ }不能同时省略
*/
def main(args: Array[String]): Unit = {
println(add2(2, 3))
printHello2("lisi")
//如果定义方法的时候没有(),那么在调用方法的时候也不能带上()
printName2
printName()
printName
}
//基本定义方法的语法
def add(x:Int,y:Int):Int = {
x+y
}
//如果方法体中只有一行语句,{}可以省略
def add2(x:Int,y:Int):Int = x+y
//基本语法
def printHello(name:String):Unit = {
println(s"hello ${name}")
}
//如果方法不需要返回值,那么=可以省略
def printHello2(name:String) {
println(s"hello ${name}")
}
//基本语法
def m1(x:Int,y:Int):Int = {
x+y
}
//如果使用方法体{ }中最后一个表达式的结果值作为方法的返回值,那么此时返回值类型可以省略
def m2(x:Int,y:Int) = {
x+y
}
//如果方法体中有return关键字必须定义返回值类型
def m3(x:String) = {
/* if(x==null) return null;
return "hello";*/
if(x==null) {
null
}else{
"hello"
}
}
//基本语法
def printName():Unit = {
println(".............")
}
//如果方法不需要参数,那么定义方法的是()可以省略
def printName2:Unit = {
println("............")
}
/**
* 在简化的时候,=与{}不能同时省略
*/
def printName3 = println("............")
1.3.Scala方法参数
/**
* java方法参数:
* 1、public 返回值类型 方法名(类型 参数名,..) { 方法体 }
* 2、可变参数: public 返回值类型 方法名(类型... 参数名) { 方法体 }
* scala方法的参数
* 1、正常形式: def 方法名(参数名:类型,..):返回值类型 = {方法体}
* 2、默认值: def 方法名(参数名:类型=默认值,..):返回值类型 = {方法体}
* 如果默认值单独使用,在定义方法的时候需要将默认值定义在参数列表最后面
* 3、带名参数:
* 指调用方法的时候将指定值传递给哪个参数: 方法名(参数名=值)
* 4、可变参数: def 方法名(参数名:参数类型,..,参数名:参数类型*)
* 可变参数必须定义在参数列表的最后面
* 可变参数不能与默认值参数、带名参数一起使用
* 可变参数不能直接传递集合,但是可以通过 集合名称:_* 的方式将集合的所有元素传递给可变参数
*
* @param args
*/
def main(args: Array[String]): Unit = {
println(add(2, 3))
println(add2())
// 如果默认值单独使用,在定义方法的时候需要将默认值定义在参数列表最后面
println(add3(10))
//带名参数: 指调用方法的时候将指定值传递给哪个参数
println(add4(y=10))
println(add5(10,20,3,4,5,6,7,8))
val paths = getPaths(7,"/user/warehouse/hive/user_info")
readPaths(paths:_*)
}
def add(x:Int,y:Int) = x+y
//默认值: def 方法名(参数名:类型=默认值,..):返回值类型 = {方法体}
def add2(x:Int=10,y:Int=20) = x+y
// 如果默认值单独使用,在定义方法的时候需要将默认值定义在参数列表最后面
def add3(y:Int,x:Int=10) = x+y
def add4(x:Int=10,y:Int) = x+y
def add5(x:Int,y:Int,z:Int*) = {
x+y+z.sum
}
/**
* /user/warehouse/hive/user_info/20201017
* /user/warehouse/hive/user_info/20201016
* /user/warehouse/hive/user_info/20201015
* /user/warehouse/hive/user_info/20201014
* /user/warehouse/hive/user_info/20201013
* /user/warehouse/hive/user_info/20201012
* /user/warehouse/hive/user_info/20201011
* /user/warehouse/hive/user_info/20201010
*
* 需求: 统计前7天的用户注册数
*/
def readPaths(path:String*): Unit ={
//模拟读取数据
println(path.toBuffer)
}
def getPaths(n:Int,pathPrefix:String) = {
//获取当前日期
val currentDate = LocalDateTime.now()
for(i<- 1 to n) yield {
//日期加减法
val time = currentDate.plusDays(-i)
//拼接路径
val str = time.format(DateTimeFormatter.ofPattern("yyyyMMdd"))
s"${pathPrefix}/${str}"
}
}
2.Scala中函数的定义
/**
* 函数的语法: val 函数名 = (参数名:参数类型,....) => { 函数体 }
* 函数的返回值就是函数体的块表达式的结果值
* 函数不可以重载,因为函数名其实就是变量名,同一作用域不能存在同名参数
*
* 函数的简化:
* 1、如果函数体中只有一行语句,{}可以省略
*
* 函数在调用的时候必须带上()
*/
def main(args: Array[String]): Unit = {
println(add(2, 3))
//方法就是函数,函数也是对象
println(add(2,3))
println(add2(2,3))
println(add3(2,3))
println(add4)
}
val add = (x:Int,y:Int) => {
x-y
}
val add4 = () => 10 * 10
val add3 = (x:Int,y:Int) => x+y
//函数不可以重载,因为函数名其实就是变量名,同一作用域不能存在同名参数
/* val add = (x:Int) => {
x-10
}*/
val add2 = new Function2[Int,Int,Int] {
override def apply(v1: Int, v2: Int): Int = v1-v2
}
3.Scala中方法和函数的区别
/**
* 方法和函数的区别:
* 1、方法如果定义在类里面,可以重载,函数因为是对象,所以不能重载
* 2、方法是保存在方法区,函数是对象保存在堆里面
* 联系:
* 1、如果方法定义在方法里面,它其实就是函数
* 2、方法可以手动转成函数: 方法名 _
*/
def main(args: Array[String]): Unit = {
val f = m1 _
println(f(2,3))
}
/**
* 方法重载
*/
def add(x:Int,y:Int):Int = x+y
def add(x:Int) = x * x
val func = (x:Int,y:Int) => x+y
//val func = (x:Int) => x*x
def m1(x:Int,y:Int) = x+y
4.高阶函数
/**
* 高阶函数: 以函数作为参数或者返回值的方法/函数称之为高阶函数
*
*
*/
def main(args: Array[String]): Unit = {
val func = (x:Int,y:Int) => x+y
println(add(10, 20, func))
//方法就是函数
//println(add(3,5,m1 _))
println(add(3,5,m1))
}
/**
* 高阶函数
* @param x
* @param y
* @param func 函数对象,封装的操作
* @return
*/
def add(x:Int,y:Int,func: (Int,Int)=>Int ) = {
func(x,y)
}
def m1(x:Int,y:Int) = x*y
4.1高阶函数的简化
/**
* 高阶函数的简化:
* 1、将函数作为值进行传递
* 2、函数的参数类型可以省略
* 3、如果函数的参数在函数体中只使用了一次,那么可以用_代替
* 1、如果在函数体中参数的使用顺序与参数的定义顺序不一致,不能用_代替
* 2、如果函数的参数只有一个,并且在函数体中没有做任何操作直接将函数的参数返回,此时也不能用_代替
* 4、如果函数只有一个参数,函数参数列表的()可以省略
*
*/
def main(args: Array[String]): Unit = {
val func = (x:Int,y:Int)=>x*y
println(add(3, 5, func))
//1、将函数作为值进行传递
println(add(3,5, (x:Int,y:Int)=>x*y ))
//2、函数的参数类型可以省略
println(add(3,5, (x,y)=>x*y ))
//3、如果函数的参数在函数体中只使用了一次,那么可以用_代替
// 前提:
// 1、如果在函数体中参数的使用顺序与参数的定义顺序不一致,不能用_代替
// 2、如果函数的参数只有一个,并且在函数体中没有做任何操作直接将函数的参数返回,此时也不能用_代替
// 3、如果函数体中有嵌套,并且函数的参数处于嵌套中以表达式的方法存在,,此时也不能用_代替
println(add(3,5, _+_ ))
// 1、如果在函数体中参数的使用顺序与参数的定义顺序不一致,不能用_代替
println(add(3,5, (x,y)=>y-x )) //不能用_简化
//println(add(3,5,_-_))
val func2 = (x:Int) => x
println(m1(5, func2))
println(m1(5, (x:Int) => x))
println(m1(5, (x) => x))
//不能用_简化
val result = m1(5, _)
//println(m1(5, _))
//
//println(result(func2))
//4、如果函数只有一个参数,函数参数列表的()可以省略
println(m1(5, x => x))
val func10 = (x:Int) => (x+10)*2
println(add3(10, x => (x+10)*2))
println(add3(20,x=>(x)+10))
println(add3(20,(_)+10))
}
def add(x:Int,y:Int,func: (Int,Int)=>Int ) = func(x,y)
def m1(x:Int, func: Int => Int) = func(x)
def add3(x:Int,func: Int=>Int) = func(x)
4.2高阶函数例子
/**
* 1、定义一个高阶函数,按照指定的规则对集合里面的每个元素进行操作
* 比如: val arr = Array[String]("spark","hello","java","python")
* 对集合中每个元素进行操作,得到集合每个元素的长度
* val result = Array[Int](5,5,4,6)
*/
def main(args: Array[String]): Unit = {
val arr = Array[String]("spark","hello","java","python")
val func = (x:String) => x.charAt(2).toInt
val result = map(arr,func)
println(result.toBuffer)
}
def map(arr:Array[String],func: String => Int)={
for(element<- arr) yield {
func(element)
}
}
4.3定义高阶函数对元素进行聚合
/**
* 2、定义一个高阶函数,按照指定的规则对集合中的所有元素进行聚合
* val arr =Array[Int](10,2,4,6,1,8,10)
* 求得集合中的所有元素的和
* val result = xx
*/
def main(args: Array[String]): Unit = {
val arr =Array[Int](10,2,4,6,1,8,10)
val func = (agg:Int,curr:Int)=> agg * curr
println(reduce(arr, func))
//1、将函数作为参数直接传递
println(reduce(arr, (agg:Int,curr:Int)=> agg * curr))
//2、函数的参数类型可以省略
println(reduce(arr, (agg,curr)=> agg * curr))
//3、函数的参数在函数体中只使用了一次,可以用_代替
println(reduce(arr, _ * _))
}
def reduce( arr:Array[Int],func: (Int,Int)=>Int )={
var tmp:Int = arr(0)
for(i<- 1 until arr.length) {
tmp = func(tmp,arr(i))
}
tmp
}
4.4定义高阶函数求最大元素
/**
* 3、定义一个高阶函数,按照指定的规则获取指定最大元素
* val arr = Array[String]("zhangsan 20 3000","lisi 30 4000","wangwu 15 3500")
* 获取年龄最大的人的数据
* val result = "lisi 30 4000"
*
*/
def main(args: Array[String]): Unit = {
val arr = Array[String]("zhangsan 20 3000","lisi 30 4000","wangwu 15 3500")
val func = (x:String,y:String) => {
val first = x.split(" ")(2).toInt
val last = y.split(" ")(2).toInt
if(first>last) {
x
}else{
y
}
}
println(maxBy1(arr, func))
println(maxBy2(arr, (x: String) => x.split(" ")(2).toInt))
}
def maxBy1( arr:Array[String], func: (String,String)=> String)={
var tmp = arr(0)
for(i<- 1 until arr.length){
tmp = func(tmp,arr(i))
}
tmp
}
def maxBy2( arr:Array[String],func: String=>Int) = {
var tmp = func(arr(0))
var result = arr(0)
for(element<- arr){
if(tmp<func(element)){
tmp = func(element)
result = element
}
}
result
}
4.6定义高阶函数进行分组
/**
* 4、定义一个高阶函数,按照指定的规则对数据进行分组
* val arr = Array[String]("zhangsan 男 深圳","lisi 女 深圳","王五 男 北京")
* 根据性别进行分组
* val result = Map[String,List[String]](
* "男"-> List("zhangsan 男 深圳","王五 男 北京"),
* "女" -> List("lisi 女 深圳")
* )
*
*/
def main(args: Array[String]): Unit = {
val arr = Array[String]("zhangsan 男 深圳","lisi 女 深圳","王五 男 北京")
val func = (x:String) => x.split(" ")(1)
println(groupBy(arr, func))
println(groupBy(arr,(x:String) => x.split(" ")(1)))
println(groupBy(arr,(x) => x.split(" ")(1)))
println(groupBy(arr,x => x.split(" ")(1)))
println(groupBy(arr,_.split(" ")(1)))
}
def groupBy( arr:Array[String],func: String=>String )={
//1、创建一个分组的存储容器
val result = new util.HashMap[String,util.List[String]]()
//2、遍历集合所有元素
for(element<- arr){
//得到分组的key
val key = func(element)
//3、判断分组的key是否在容器中存在,如果不存在,则直接添加到容器中
if(!result.containsKey(key)){
val list = new util.ArrayList[String]()
list.add(element)
result.put(key,list)
}else{
//4、如果存在,此时应该取出key对应的List,将元素添加到List
val list = result.get(key)
list.add(element)
}
}
//5、返回结果
result
}
4.7定义高阶函数对元素进行过滤
/**
* 5、定义一个高阶函数,按照指定的规则对数据进行过滤,保留符合要求的数据
* val arr =Array[Int](10,2,4,6,1,8)
* 只保留偶数数据
* val result = Array[Int](10,2,4,6,8)
*/
def main(args: Array[String]): Unit = {
val arr =Array[Int](10,2,4,6,1,8)
println(filter(arr, x => x % 2 == 0).toBuffer)
}
def filter( arr: Array[Int], func: Int => Boolean )={
for(element<- arr if( func(element) )) yield {
element
}
}
5.匿名函数
/**
* 匿名函数: 没有函数名的函数
* 匿名函数不能单独使用,只能将匿名函数作为高阶函数的参数进行传递
*/
def main(args: Array[String]): Unit = {
val func = (x:Int,y:Int) => x+y
println(func(20, 10))
//(x:Int,y:Int) => x+y
def add(x:Int,y:Int,func: (Int,Int)=>Int) = {
func(x,y)
}
println(add(10, 20, (x: Int, y: Int) => x + y ))
}
6.柯里化
/**
* 柯里化: 有多个参数列表的方法称之为柯里化
* @param args
*/
def main(args: Array[String]): Unit = {
println(add(10, 20,30))
println(add2(10, 20)(30))
val func = add3(10,20)
println(func(30))
println(add3(10, 20)(30))
println(add4(10,20)(30))
val func2 = add2 _
val func3 = add3 _
}
def add(x:Int,y:Int,z:Int) = x+y+z
//柯里化
def add2(x:Int,y:Int)(z:Int) = x+y+z
/**
* 柯里化演变过程
*/
def add3(x:Int,y:Int) = {
val func = (z:Int) => x+y+z
func
}
def add4(x:Int,y:Int) = {
// Person p = new Person
// return new Person;
//val func = (z:Int) => x+y+z
//func
(z:Int) => x+y+z
}
7.闭包
/**
* 闭包: 函数体中使用了不属于自身的变量的函数
* @param args
*/
def main(args: Array[String]): Unit = {
println(func(100))
}
val b = 10
/**
* 闭包
*/
val func = (x:Int) => {
val c = 10
x + c + b
}
def add(x:Int,y:Int) = {
/* val func = (z:Int)=> {
val func2 = (a:Int)=> a+x+y+z
func2
}
func*/
(z:Int)=> {
(a:Int)=> a+x+y+z
}
}
8.递归
/**
* 递归: 自己调用自己称之为递归
* 前提:
* 1、必须要有退出条件
* 2、递归必须定义返回值类型
*/
def main(args: Array[String]): Unit = {
println(m1(5))
}
def m1(n:Int):Int = {
if(n==1){
1
}else{
n * m1(n-1)
}
}
9.惰性求值
/**
* 惰性求值: 变量只有在真正使用的时候才会赋值
* @param args
*/
def main(args: Array[String]): Unit = {
lazy val name = "zhangsan"
val age = 20
println(name)
println(age)
}
10.控制抽象
/**
* 控制抽象: 其实就是一个块表达式,可以将块表达式作为参数[ => 块表达式的结果值类型 ]传递给方法,后续当做函数进行调用
*
* 控制抽象只能用于方法的参数
* 控制抽象在调用的时候不能带上()
* @param args
*/
def main(args: Array[String]): Unit = {
val b = {
println("xxxxxxxxxxxx")
val c = 20
c * c
}
def m1(x:Int) = {
println(x*x)
}
m1({
println("xxxxxxxxxxxx")
val c = 20
c * c
})
def m2(x:Int,func: Int=>Int) = {
func(x)
func(x)
func(x)
}
m2(10,x=>{
println(".....................")
x+10
})
var i = 0
breakable({
while (i<=10){
if(i==5) break()
println(s"i=${i}")
i=i+1
}
})
val func2 = () => println("hello.........")
func2()
m4({
println("+++++++")
false
})
println("*"*100)
var j = 0
myLoop({
j<=10
})({
println(s"j=${j}")
j = j+1
})
}
def m4(f1: => Unit) = {
//在调用控制抽象的时候不能带上()
f1
f1
f1
}
def myLoop(condition: =>Boolean)(body: =>Unit):Unit = {
if(condition) {
body
myLoop(condition)(body)
}
}
第 4 章 类和对象
1.Scala定义类
//如果class中没有任何东西,{}可以省略
class Person
/**
* java class创建语法: 修饰符 class 名称{...}
*
* scala里面没有public关键字,默认就是public
* scala创建class的语法: class 名称 {...}
* scala创建对象: new class名称(..)
*/
def main(args: Array[String]): Unit = {
//如果使用无参的构造器,()可以省略
val person = new Person
println(person)
}
1.1定义类中属性和方法
class Person{
//定义属性: 修饰符 val/var 属性名:类型 = 值
//val定义的属性不可被修改
//var定义的属性可以被修改
//@BeanProperty注解不能用在private修饰的属性上
@BeanProperty
var name = "zhangsan"
@BeanProperty
var age = 20
/* def setName(name:String) = this.name=name
def getName() = this.name
def setAge(age:Int) = this.age = age
def getAge() = this.age*/
//scala中属性有默认的get/set方法,get的方法名其实就是属性名,set的方法名其实就是 属性名=
//在class中var修饰的属性可以使用_初始化,使用_初始化的时候必须指定属性的类型
var address:String = _
//setXXx getXXx
//JSON解析
//定义方法: 修饰符 def 方法名(参数名:参数类型,...):返回值类型 = {方法体}
def printName () = println(s"name=${name}")
//定义函数: 修饰符 val 函数名 = (参数名:参数类型,...) => {函数体}
val func = (x:Int,y:Int) => x+y
}
def main(args: Array[String]): Unit = {
val person = new Person
println(person.name)
println(person.age)
println(person.address)
person.age=(100)
println(person.age)
person.printName()
println(person.func(10, 20))
println("*"*100)
val json = """{"name":"lisi","age":100}"""
//json转对象
val person2 = JSON.parseObject(json,classOf[Person])
println(person2.name)
println(person2.age)
}
1.2 scala中构造方法
def this(name:String) {
//第一行必须调用其他的辅助构造器或者主构造器
this(name=name,address="beijing")
//this("lisi",100)
}
def this(age:Int) {
this("zhaoliu")
}
def this(name:String,age:Int) {
this(name=name,address="beijing")
}
}
/**
* java中构造方法的定义: 修饰符 类名(参数类型 参数名,..) {..}
*
* scala中构造方法分为两种:
* 1、主构造器: 定义类名后面{}之前,通过()表示
* 主构造器中属性的定义: [修饰符] [val/var] 属性名:类型 = 默认值
* 柱构造器中val/var以及不写val/var的区别:
* val定义的属性不能更改
* var定义的数可以更改
* 使用val/var修饰的非private的属性既可以在class内部使用也可以在class外部使用
* 不用val/var修饰的属性只能在class内部使用
* 2、辅助构造器
* 辅助构造器定义在class里面
* 语法: def this(参数名:参数类型,...){
* //第一行必须调用其他的辅助构造器或者主构造器
* this(..)
* }
*
*/
def main(args: Array[String]): Unit = {
val person = new Person("lisi",100,"shenzhen")
println(person.name)
println(person.age)
println(person.getName)
val person2 = new Person("lisi")
println(person2.getName)
val person3 = new Person(100)
println(person3.getName)
}
1.3 封装
class Person{
@BeanProperty
val name:String = "zhangsan"
//def getName() = this.name
}
/**
* 封装: 属性私有,提供公有的set/get方法
*
* scala中属性一般不私有,通过@BeanProperty注解提供公有的set/get方法
* @BeanProperty对于val修饰的属性只提供get方法
* 对于var修饰的属性提供set与get方法
*/
def main(args: Array[String]): Unit = {
// println($06_Package.AAAAAAA)
val person = new Person
println(person.getName)
}
1.4继承
/*final */class Animal{
/*private */
@BeanProperty val name:String = "zhangsan"
@BeanProperty var age:Int = _
def printHello() = println("...........")
}
class Dog extends Animal{
override val name = "lisi"
override def printHello(): Unit = {
println("888888888888888888888888")
super.printHello()
}
}
/**
* scala中通过extends关键字来实现继承关系
*哪些情况不能被继承:
* 1、private修饰的属性/方法/函数不能被继承
* 2、final修饰的class不能被继承
*子类可以通过override关键字来重写父类的方法/val修饰的属性
*
* var修饰的属性不能通过override来重写
* 子类中可以通过super关键字来调用父类的方法
*
* java中的多态只是方法的多态,属性不多态
* scala中方法和属性都是多态的
*/
def main(args: Array[String]): Unit = {
val dog = new Dog
println(dog.name)
println(dog.age)
dog.printHello()
val animal:Animal = new Dog
animal.printHello()
println(animal.getName)
println(CCCCCCCCCC)
}
1.5scala中包的作用
{
private[chapter06] val AAAAAAA="lisi"
/**
* 包的作用:
* 1、区分同名
* 2、便于管理
* java中对于包的申明方式:
* 1、通过package 包名在.java源文件的第一行
* java中对于包的使用:
* 1、import 包名.*
* 2、import 包名.类名
*java中import导入包必须在声明包后面,class前面
*
* scala中对于包的申明方式:
* 1、通过package 包名在.java源文件的第一行
* 2、通过package 包名{}[通过该方式声明的包在项目结构下看不到但是在target目录下可以看到]
* scala中对于包的使用:
* 1、导入包下所有类: import 包名._
* 2、导入包下某个类: import 包名.类名
* 3、导入包下多个类: import 包名.{类名1,类名2,..}
* 4、导入包下某个类,并起别名: import 包名.{类名=>别名}
* 5、导入包下除开某个类的其他类: import 包名.{类名=>_,_}
* scala可以在任何地方导入包。
* 如果是在父作用域中导入的包,子作用域可以使用
* 子作用域导入的包,父作用域不可以使用
* scala中访问修饰符可以搭配package使用: private[包名] val 属性名:类型 = 值 【代表该属性只能在该包下使用】
*
* 包对象:
* 语法: package object 包名{...}
* 包对象中非private修饰的属性/方法/函数可以在包下任何地方使用
*/
def main(args: Array[String]): Unit = {
import scala.util.control.Breaks._
val scalaMap = new mutable.HashMap[String,String]()
}
}
package bb{
class Student
}
1.6 抽象类
abstract class Animal{
//抽象属性
val name:String
//具体属性
var age:Int = 10
//抽象方法
def m1(x:Int,y:Int)
//具体方法
def add(x:Int,y:Int) = x*y
}
class Dog extends Animal {
//具体方法
override def m1(x: Int, y: Int): Unit = x+y
//重写抽象属性
override val name: String = "lisi"
}
/**
* 抽象类:
* 1、语法: abstract class 类名{....}
* 2、scala的抽象类中可以定义抽象方法,也可以定义具体方法
* scala中抽象类中可以定义抽象属性,也可以定义具体属性
* 抽象方法: 没有方法体的方法称之为抽象方法,定义抽象方法的时候如果不定义返回值类型,返回值默认就是Unit
* 抽象属性: 没有赋予初始值的属性【定义抽象属性的时候,属性的类型必须定义】
*
*/
def main(args: Array[String]): Unit = {
val dog = new Dog
println(dog.m1(10, 20))
println(dog.name)
println(dog.age)
//匿名子类
val p = new Animal {
override val name: String = "zhangsan"
override def m1(x: Int, y: Int): Unit = println(s"${x} ${y}")
}
println(p.name)
p.m1(10,20)
}
1.7 伴生类和伴生对象
object $08_SingleObject {
class Person(val age:Int){
private val name = "艾尔"
def this() = {
this(10)
}
def xx = Person.printHello()
}
object Person{
val age = 100
private def printHello() = {
val person = new Person(20)
println(person.name)
}
def apply(age:Int) = new Person(age)
def apply() = new Person
}
//val name = "xxx"
/**
* 单例对象的语法: object xx{...}
*
* object中所有的方法/属性/函数都是类似java static修饰的。可以通过 object名称.属性/方法/函数 的方法调用
*
* 伴生类和伴生对象
* 1、class与object的名称要一致
* 2、class与object要在同一个.scala文件中
*
* 伴生类和伴生对象可以互相访问对方private修饰的属性/方法/函数
*
* apply方法: 主要用来简化伴生类的对象创建
* 后续可以通过 object名称.apply(..) / object名称(..) 创建伴生类的对象
* @param args
*/
def main(args: Array[String]): Unit = {
val obj1 = $08_SingleObject
val obj2 = $08_SingleObject
println(obj1)
println(obj2)
//println($08_SingleObject.name)
val person = new Person(20)
person.xx
val person4 = Person.apply(10)
person4.xx
val person5 = Person(10)
person5.xx
val arr = Array[Int](10,20,30,40)
val p = Person()
}
}
2. 特质
trait Logger{
//抽象属性
val name:String
//具体属性
val age:Int = 20
//抽象方法
def add(x:Int,y:Int):Int
//具体方法
def m1(x:Int) = x * x
}
trait Logger2
class A
class WarnLogger extends A with Logger with Logger2 {
override val name: String = "zhangsan"
override def add(x: Int, y: Int): Int = x+y
}
/**
* 语法: trait 特质名{....}
* 在trait中既可以定义抽象方法也可以定义具体方法
* 既可以定义抽象字段也可以定义具体字段
*
* 子类如果需要继承父类,extends关键字用来继承父类,trait的实现通过with关键字来做
* 子类如果不需要继承父类,extends关键字用来继承第一个trait,后续其他的trait通过with关键字实现
*
*/
def main(args: Array[String]): Unit = {
//匿名子类
val logger = new Logger {
override val name: String = "lisi"
override def add(x: Int, y: Int): Int = x * y
}
println(logger.add(10, 20))
val warn = new WarnLogger
println(warn.add(100,200))
}
2.1对象混入
trait Logger{
def add(x:Int,y:Int) = x+y
}
class Warnlogger
/**
* 对象混入: 只让某个对象拥有特质的属性和方法
* 语法: new class名称 with 特质名
* @param args
*/
def main(args: Array[String]): Unit = {
val warnlogger = new Warnlogger with Logger
println(warnlogger.add(10, 20))
val a = new Warnlogger
//a.add()
}
2 .2 trait方法
trait ParentLogger{
def log(msg:String) = println(s"ParentLogger:${msg}")
}
trait Logger1 extends ParentLogger{
override def log(msg:String) = {
println(s"Logger1:${msg}")
}
}
trait Logger2 extends ParentLogger{
override def log(msg:String) = {
println(s"Logger2:${msg}")
}
}
trait Logger3 extends ParentLogger{
override def log(msg:String) = {
println(s"Logger3:${msg}")
}
}
class A extends Logger1 with Logger2 with Logger3{
override def log(msg: String): Unit ={
println(s"A:${msg}")
super[Logger2].log(msg)
}
}
/**
* scala可以多实现,如果实现的多个trait中有同名方法,子类实现这多个trait之后相当于有多个同名方法
* 解决方案:
* 1、在子类中重写父trait的同名方法
* 2、创建一个新trait,在新trait中创建一个同名方法,子类的父trait全部继承该新trait。
* 如果父trait中有通过super关键字调用同名方法,此时调用顺序是按照继承顺序从右向左开始调用
* @param args
*/
def main(args: Array[String]): Unit = {
val a = new A
a.log("xxxx")
}
2.3 对象的序列化
class Logger
trait ReadAndWrite{
_:Serializable =>
/**
* 从磁盘读取对象
*/
def read() = {
val ois = new ObjectInputStream(new FileInputStream("d:/obj.txt"))
val obj = ois.readObject()
ois.close()
obj
}
/**
* 将当前对象写入磁盘
*/
def write() = {
val oos = new ObjectOutputStream(new FileOutputStream("d:/obj.txt"))
oos.writeObject(this)
oos.close()
}
}
class Person(val name:String,val age:Int) extends ReadAndWrite with Serializable
/**
* 定义一个trait,trait中自带read、write两个方法能够实现将当前对象读取/写入到磁盘
*
* 自身类型: 子类在实现trait的时候提示必须要先继承/实现某个类型
*/
def main(args: Array[String]): Unit = {
val person = new Person("lisi",20)
person.write()
val p = new Person("zhangsan",30)
val obj = p.read()
println(obj.asInstanceOf[Person].name)
}
3. Scala类型检查
class Animal{
def xx() = println("Animal")
}
class Dog extends Animal{
val name= "xx"
override def xx() = println("Dog")
}
class Pig extends Animal{
val age= 20
override def xx() = println("Dog")
}
def getAnimal() = {
val r = Random.nextInt(10)
if(r%5==0)
new Dog
else if(r%2==0)
new Pig
else
new Animal
}
/**
* java类型判断: 对象 instanceof 类型
* java中类型的强转: (类型)对象
*
* scala类型判断: 对象.isInstanceOf[类型]
* scala中类型强转: 对象.asInstanceOf[类型]
*
* java中获取对象的class形式: 对象.getClass()
* java中获取类的class形式: 类名.class
*
* scala中获取对象的class形式: 对象.getClass()
* scala中获取类的class形式: classOf[类名]
*
*
*/
def main(args: Array[String]): Unit = {
val animal = getAnimal()
println(animal.getClass)
if(animal.isInstanceOf[Animal]){
val pig = animal.asInstanceOf[Pig]
println(pig.age)
}else{
val dog = animal.asInstanceOf[Dog]
println(dog.name)
}
}
4. 枚举类
object Test20 extends App {
println("xxxxxxxxxxx");
}
object $14_App {
// 枚举类
object Color extends Enumeration {
val RED = Value(1, "red")
val YELLOW = Value(2, "yellow")
val BLUE = Value(3, "blue")
}
def main(args: Array[String]): Unit = {
println(Color.RED)
}
}
5. 类起别名
/**
* 新类型: 给类起别名
* type myarr = Array[String]
*/
def main(args: Array[String]): Unit = {
type s = String
type myarr = Array[String]
val name:s = "name"
val arr:myarr = Array[String]("....")
}
第 5 章 数组和集合
5.1 数组
5.1.1不可变数组
/**
* 1、不可变数组的创建方式:
* 1、Array[元素类型](初始元素,..)
* 2、new Array[元素的类型](数组的长度)
*
* 2、插入数据
* 3、删除数据
* 4、获取数据
* 5、修改数据
*
* 一个+与两个+的区别:
* 一个+ 是添加单个元素
* 两个+ 是添加一个集合的所有元素
* 冒号在前与冒号在后的区别:
* 冒号在前 是将元素添加在集合的最末尾
* 冒号在后 是将元素添加在集合的最前面
* 不带冒号 是将元素添加在集合的最末尾
*/
def main(args: Array[String]): Unit = {
//Array[元素类型](初始元素,..)
val arr = Array[Int](10,2,4,6,1)
println(arr.toBuffer)
//new Array[元素的类型](数组的长度)
val arr2 = new Array[Int](10)
println(arr2.toBuffer)
//添加数据
val arr3 = arr.+:(20)
println(arr3.toBuffer)
println(arr.toBuffer)
val arr4 = arr.:+(30)
println(arr4.toBuffer)
//添加一个集合所有元素
val arr5 = arr.++(Array(100,200,300))
println(arr5.toBuffer)
val arr6 = arr.++:(Array(400,500,600))
println(arr6.toBuffer)
//获取元素
val element = arr6(2)
println(element)
//修改元素
arr6(2)=1000
//将不可变数组转可变数组
println(arr6.toBuffer)
for(i<- arr){
println(i)
}
}
5.1.2 可变数组
/**
* 1、可变数组的创建:
* 1、ArrayBuffer[元素类型](初始元素,...)
* 2、new ArrayBuffer[元素类型]()
* 2、添加元素
* 3、删除元素
* 4、修改元素
* 5、获取元素
* 集合方法的区别:
* 一个+/-与两个+/-的区别:
* 一个+/-是添加单个元素
* 两个+/-是添加一个集合的所有元素
* 冒号在前与冒号在后以及不带冒号的区别:
* 冒号在前是将元素添加在集合的末尾
* 冒号在后是将元素添加在集合的最前面
* 不带冒号是将元素添加在集合的末尾
* 带=与不带=的区别:
* 带=是修改集合本身
* 不带=是生成新集合,原有集合没有改变
* +与-的区别:
* +是指添加元素
* -是指删除元素
*/
def main(args: Array[String]): Unit = {
//1、ArrayBuffer[元素类型](初始元素,...)
val arr = ArrayBuffer[Int](2,5,7,1,3)
println(arr)
//2、new ArrayBuffer[元素类型]()
val arr2 = new ArrayBuffer[Int]()
println(arr2)
//添加元素
val arr3 = arr.+:(10)
println(arr3)
println(arr)
arr.+=(20)
println(arr)
arr.+=:(30)
println(arr)
val arr4 = arr.++(Array(100,200))
println(arr4)
val arr5 = arr.++:(Array(300,400))
println(arr5)
arr.++=(Array(1000,3000))
println(arr)
arr.++=:(Array(400))
println(arr)
arr.+=:(500)
arr.+=:(400)
println("*"*100)
println(arr)
//删除元素
val arr6 = arr.-(400)
println(arr6)
arr.-=(1000)
println(arr)
val arr7 = arr.--(Array(400,500,30))
println(arr7)
arr.--=(Array(2,5,7,50))
println(arr)
//获取元素
println(arr(2))
//修改元素
arr(2)=50
println(arr)
//可变数组转不可变数组
println(arr.toArray)
//多维数组
val array = Array.ofDim[Int](3,4)
println(array.length)
println(array(0).length)
}
5.1.2 List
/**
* 1、创建方式:
* 1、List[元素类型](初始元素,...)
* 2、元素 :: 元素 :: .. :: list/Nil
* :: 最后面必须要是一个List或者是Nil
* Nil就是相当于是List的子类
*
* ::与:::的区别:
* ::是添加单个元素
* ::: 是添加一个集合的所有元素
*/
def main(args: Array[String]): Unit = {
//1、List[元素类型](初始元素,...)
val list = List[Int](10,20,30)
println(list)
//元素 :: 元素 :: .. :: list/Nil
val list2 = 10 :: 20 :: 30 :: Nil
println(list2)
var list3:List[Int] = Nil
list3 = list2
//2、添加元素
val list4 = list2.:+(50)
println(list4)
val list6 = list2.+:(60)
println(list6)
val list7 = list2.++(Array(100,200,300))
println(list7)
val list8 = list2.++:(Array(400,500,600))
println(list8)
val list9 = 100 :: list8
println(list9)
val list10 = list9 ::: list
println(list10)
//获取元素
println(list10(2))
//修改元素
//list10(2) = 1000
val list11 = list10.updated(2,1000)
println(list11)
//List转数组
println(list11.toBuffer)
}
5.1.3可变List
/**
* 1、创建方式: ListBuffer[元素类型](初始元素,....)
*/
def main(args: Array[String]): Unit = {
//创建方式: ListBuffer[元素类型](初始元素,....)
val list = ListBuffer[Int](10,20,30)
println(list)
//添加元素
val list2 = list.+:(40)
println(list2)
val list3 = list.:+(50)
println(list3)
list.+=(60)
println(list)
list.+=:(70)
println(list)
val list5 = list.++(Array(80,90,100))
println(list5)
val list6 = list.++:(Array(200,300))
println(list6)
list.++=(Array(100,200))
println(list)
list.++=:(Array(1000,2000))
println(list)
list.append(500,600,700)
println(list)
//删除元素
val list8 = list.-(1000)
println(list8)
list.-=(2000)
println(list)
val list9 = list.--(Array(10,20,30))
println(list9)
list.--=(Array(500,600,700))
println(list)
list.remove(0)
println(list)
//获取元素
println(list(0))
//修改
list(0)=1000
println(list)
list.update(1,200)
println(list)
val list10 = list.updated(3,500)
println(list10)
}
不可变set
/**
* set的特点: 无序、不重复
* 创建方式: Set[元素类型](初始元素,...)
*/
def main(args: Array[String]): Unit = {
val set = Set[Int](1,5,5,2,10,3)
println(set)
//添加元素
val set2 = set.+(20)
println(set2)
val set3 = set.++(Array(100,500,200))
val set4 = set.++:(Array(100,500,200))
println(set3)
println(set4)
//删除元素
val set5 = set4.-(500)
println(set5)
val set6 = set4.--(Array(2,10,100))
println(set6)
//获取元素
//修改元素
for(i<- set4){
println(i)
}
}
可变set
def main(args: Array[String]): Unit = {
//创建方式: mutable.Set[元素类型](初始元素,...)
val set = mutable.Set[Int](10,2,6,1,3)
println(set)
//添加元素
val set2 = set.+(10)
set.+=(20)
println(set2)
println(set)
val set3 = set.++(Array(100,200))
val set4 = set.++:(Array(100,200))
set.++=(Array(300,400))
println(set3)
println(set4)
println(set)
set.add(1000)
println(set)
//删除元素
val set5 = set.-(300)
set.-=(400)
println(set5)
println(set)
val set6 = set.--(Array(300,2,20))
set.--=(Array(10,2,1,6))
println(set6)
println(set)
set.remove(1000)
println(set)
//set.update()
}
元组
object $07_Tuple {
class Person(val name:String,val age:Int,val address:String)
class School(val name:String,val clazz:Clazz)
class Clazz(val name:String,val student:Student)
class Student(val name:String,val age:Int)
/**
* 创建方式:
* 1、通过()方式创建: (初始元素,..)
* 2、如果是创建二元元组,还可以 K->V 的方式创建
* 元组一旦创建,长度以及元素都不可改变
* 元组最多只能存放22个元素
* 元组的值的获取: 元组的变量._角标 【角标从1开始】
*/
def main(args: Array[String]): Unit = {
//1、通过()方式创建: (初始元素,..)
val t1 = ("zhangsan",20,"beijing")
//2、如果是创建二元元组,还可以 K->V 的方式创建
val t2 = "zhangsan" -> 20
println(t1._1)
val school = new School("宝安中学",new Clazz("xx",new Student("lisi",20)))
val school2 = ("宝安中学",("xx",("lisi",20)))
println(school2._2._2._1)
}
def m1(name:String,age:Int,address:String) = {
(name,age,address)
}
}
不可变Map
/**
* 创建方式:
* 1、Map[K的类型,V的类型]( (K,V),(K,V),... )
* 2、Map[K的类型,V的类型] ( K -> V ,...)
* Map中不能有重复key
* Option: 提醒外部当前可能返回数据为空需要进行处理
* Some: 表示非空,数据封装在Some中,后续可以通过get方法获取数据
* None: 表示为空
*/
def main(args: Array[String]): Unit = {
val map = Map[String,Int]( ("zhangsan",20),("lisi",30),("zhangsan",40) )
val map2 = Map[String,Int]( "zhangsan"->20,"lisi"->30)
println(map)
println(map2)
//添加元素
val map3 = map.+("wangwu"->30)
val map4 = map.++( Map(("aa",1),("bb",2)) )
println(map3)
println(map4)
val map5 = map.++:(Map(("aa",1),("bb",2)))
println(map5)
println(map5.getClass)
//更新
val map6 = map5.updated("cc",100)
println(map6)
//获取key对应的value数据
//println(map6("dd"))
//println(map6.get("dd").get)
println(map6.getOrElse("dd", 1000))
//获取map所有的key
for(key<- map6.keys){
println(key)
}
//获取所有的value
for(value<- map6.values){
println(value)
}
}
可变Map
/**
* 创建方式:
* 1、mutable.Map[K的类型,V的类型]( (K,V),(K,V),.. )
* 2、mutable.Map[K的类型,V的类型]( K->V,.. )
* @param args
*/
def main(args: Array[String]): Unit = {
val map = mutable.Map[String,Int]( ("zhangsan",20),("lisi",30) )
val map2 = mutable.Map[String,Int]( "zhangan"->30,"lisi"->20)
println(map)
println(map2)
//添加元素
val map3 = map.+( "wangwu"->25 )
map.+=( "aa"->10)
println(map3)
println(map)
val map4 = map.++(Map[String,Int]("cc"->1,"dd"->2))
val map5 = map.++:(Map[String,Int]("ee"->10,"ff"->20,"aa"->30))
println(map4)
println(map5)
map.++=(Map[String,Int]("pp"->100,"ww"->200))
println(map)
map.put("tt",1000)
println(map)
//删除元素
val map6 = map.-("aa")
println(map6)
map.-=("ww")
println(map)
val map7 = map.--(List("lisi","tt"))
println(map7)
map.--=(List("zhangsan","pp"))
println(map)
map.remove("lisi")
println(map)
//获取元素
println(map.getOrElse("ddd",-1))
//获取所有key
for(key<- map.keys){
println(key)
}
//获取所有的vlaue
for(value<- map.values){
println(value)
}
//修改元素
map("aa")=1000
println(map)
map.update("tt",100)
println(map)
val map10 = map.updated("tt",1)
println(map10)
println(map)
}
获取集合属性
def main(args: Array[String]): Unit = {
val list = List[Int](10,20,30)
//获取集合的长度
println(list.size)
println(list.length)
//是否包含某个元素
println(list.contains(100))
//判断集合是否为空
println(list.isEmpty)
//判断集合是否不为空
println(list.nonEmpty)
//生成字符串
println(list)
println(list.mkString("#"))
}
集合方法
def main(args: Array[String]): Unit = {
//去重 *****
val list = List[Int](10,10,20,30,2,1,1,50)
val list2 = list.distinct
println(list2)
//删除前多少个元素,保留剩余的元素
val list3 = list.drop(2)
println(list3)
//删除后多少个元素,保留剩余元素
val list4 = list.dropRight(3)
println(list4)
//获取第一个元素 ****
val head = list.head
println(head)
//获取最后一个元素 *****
val last = list.last
println(last)
//获取除开最后一个元素的所有元素
val list5 = list.init
println(list5)
println("*"*100)
//除开第一个元素的所有元素
val list11 = list.tail
println(list11)
//反转
val list7 = list.reverse
println(list7)
//获取子集合
val list8 = list.slice(2,5)
println(list8)
//窗口 ******
//size: 窗口的大小
//step: 窗口滑动的长度
val list9 = list.sliding(3,2)
println(list9.toBuffer)
//获取前多少个元素 *****
val list12 = list.take(3)
println(list12)
//获取后多少个元素
val list13 = list.takeRight(3)
println(list13)
//val list = List[Int](10,10,20,30,2,1,1,50)
val list14 = List[Int](10,1,4,5,20)
//交集[两个集合共同的元素]
val list15 = list.intersect(list14)
println(list15)
//差集[ 除开交集之外的元素 A 差 B => 结果是A中除开交集之外的所有元素 ]
val list16 = list.diff(list14)
println(list16)
//并集【两个集合的所有元素,不去重】
val list17 = list.union(list14)
println(list17)
//拉链
val list18 = List[String]("aa","bb","cc","dd")
val list19 = List[Int](1,2,3)
val list20 = list18.zip(list19)
println(list20)
//反拉链
val list21 = list20.unzip
println(list21)
}
集合初级方法
def main(args: Array[String]): Unit = {
val list = List[Int](2,7,1,9,10,5,3)
//最大值
val max = list.max
//最小值
val min = list.min
println(max)
println(min)
//根据什么获取最大值
val list2 = List[String]("zhangsan 20 3000","lisi 15 5000","wangwu 30 1000")
//maxBy中的函数是针对集合的每个元素
val maxBy = list2.maxBy(x=>x.split(" ")(1).toInt)
println(maxBy)
//根据什么获取最小值
val list3 = List[(String,Int)]( ("ZHANGSAN",1000),("LISI",2500),("WANGWU",3000),("WANGWU",2500) )
//minBy中的函数是针对集合的每个元素
println(list3.minBy(_._2))
//求和
println(list.sum)
//List[String]("spark","hello").sum
//排序
//直接按照元素本身排序[升序]
val list4 = list.sorted
println(list4)
//降序
val list5 = list4.reverse
println(list5)
println(list3.sorted)
//指定按照哪个字段排序[升序] *****
println(list3.sortBy(_._2))
//根据指定的规则排序
println(list.sortWith((x, y) => x < y))
println(list.sortWith((x, y) => y < x))
}
集合高级方法
def main(args: Array[String]): Unit = {
val list = List[String]("spark","hello","java","python")
//map(func: 集合元素类型 => B ): 主要用来转换数据[转换值、转换类型]
// map中的函数是针对集合的每个元素进行操作
// map的应用场景: 一对一 【val B = A.map(..) B集合的元素的个数=A集合元素个数】
val list2 = list.map(x=>x.length)
println(list2)
val list3 = List[Int](10,20,30,40)
val list4 = list3.map(x=>x*x)
println(list4)
//foreach(func: 集合元素类型 => U ):Unit
// foreach中的函数也是针对集合的每个元素
// foreach与map的区别: map有返回值,foreach没有返回值
val list5 = List[(String,Int,String)]( ("lisi",20,"深圳"),("zhangsan",15,"北京") )
list5.foreach(println(_))
val func = (x:(String,Int,String)) => println(x)
list5.foreach(println)
//flatten-压平
//flatten只能用于集合中嵌套集合的场景
//flatten的应用场景: 一对多
val list6 = List[List[String]](
List[String]("aa","bb"),
List[String]("cc","dd"),
List[String]("ee","ff")
)
val list7 = list6.flatten
println(list7)
val list8 = List[List[List[String]]](
List(List[String]("aa","bb"),List[String]("cc","dd")),
List(List[String]("ee","ff"),List[String]("oo","xx"))
)
val list9 = list8.flatten
println(list9)
val list10 = List[String]("spark","hello")
println(list10.flatten)
//flatMap(func: 集合元素类型=> 集合 ) = map+flatten
// flatMap中的函数也是针对集合中的每个元素
// flatMap应用场景: 一对多
val list11 = List[String]("hadoop spark","hello java python")
val list12 = list11.map(x=>x.split(" "))
val list13 = list12.flatten
println(list13)
println(list11.flatMap(_.split(" ")))
//List(hadoop,spark,hello.java,python)
//filter( func: 集合元素类型 => Boolean ) - 过滤
// filter中的函数针对集合的每个元素,filter保留的是函数返回值为true的数据
val list14 = List[Int](10,2,4,5,7,9)
println(list14.filter(_ % 2 == 0))
//groupBy(func: 集合元素类型=> K ) --分组
//groupBy是根据指定的字段进行分组,里面的函数针对是集合每个元素
//groupBy的结果是Map[分组的key,List[原有集合元素类型]]
val list15 = List[(String,String)](
("ZHANGSAN","SHENZHEN"),
("LISI","BEIJING"),
("WANGWU","SHENZHEN"),
("ZHAOLIU","SHENZHEN")
)
//list15.groupBy(x=> x._2)
val list16 = list15.groupBy(_._2)
println(list16)
//reduce(func: (集合元素类型,集合元素类型) => 集合元素类型 ) --聚合
//reduce中的函数是两两聚合,然后将上一次的聚合结果与下一个元素再次聚合
//reduce最终结果是单个数据,数据的类型就是原有集合的元素类型
val list17 = List[Int](10,2,4,5,7,9)
val result = list17.reduce( (agg,curr)=>{
println(s"agg=${agg} curr=${curr}")
agg * curr
})
//reduce的执行过程:
// agg上一次的聚合结果 curr:本次要聚合元素
// 第一次执行的时候,agg的值就是集合第一个元素[10], curr集合第二个元素[2] (agg,curr)=> agg * curr = 20
// 第二次执行的时候,agg上一次的聚合结果[20], curr集合第三个元素[4] (agg,curr)=> agg * curr = 80
// ......
println(result)
//reduceRight(func: (集合元素类型,集合元素类型) => 集合元素类型 )
//reduceRight中的函数是两两聚合,然后将上一次的聚合结果与下一个元素再次聚合
//reduceRight最终结果是单个数据,数据的类型就是原有集合的元素类型
println("*"*100)
val result2 = list17.reduceRight((curr,agg)=>{
println(s"agg=${agg} curr=${curr}")
agg-curr
})
//reduceRight的执行过程:
// agg上一次的聚合结果 curr:本次要聚合元素
// 第一次执行的时候,agg的值就是集合第最后一个元素[9], curr集合倒数第二个元素[7] (agg,curr)=> agg - curr = 2
// 第二次执行的时候,agg上一次的聚合结果[2], curr集合倒数第三个元素[5] (agg,curr)=> agg * curr = -1
// ......
println(result2)
println("+"*100)
//fold(agg第一次执行的初始值)(func: (集合元素类型,集合元素类型)=>集合元素类型)
//fold与reduce唯一的不同就是多了agg的初始值
list17.fold(100)( (agg,curr)=>{
println(s"agg=${agg} curr=${curr}")
agg-curr
})
println("-"*100)
//foldRight(agg第一次执行的初始值)(func: (集合元素类型,集合元素类型)=>集合元素类型)
list17.foldRight(200)( (curr,agg)=>{
println(s"agg=${agg} curr=${curr}")
agg - curr
})
}
案例一word count
object $14_WordCount {
def main(args: Array[String]): Unit = {
val datas = List("Hello Scala Hbase kafka", "Hello Scala Hbase", "Hello Scala", "Hello")
//1、切割句子获取单词,压平
//datas.flatMap(x=>x.split(" "))
val words = datas.flatMap(_.split(" "))
//List(Hello,Scala,Hbase,kafka,Hello,Scala,Hbase,Hello,Scala,Hello)
//2、按照单词进行分组
val grouped = words.groupBy(x=>x)
/**
* Map[
* Hello -> List[Hello,Hello,Hello,Hello],
* Scala-> List[Scala,Scala,Scala],
* Hbase-> List[Hbase,Hbase],
* kafka->List[kafka]
* ]
*/
//3、统计单词的个数
val result = grouped.map(x=>{
//x = Hello -> List[Hello,Hello,Hello,Hello]
val num = x._2.length
(x._1,num)
})
//4、结果展示
result.foreach(println)
//最终结果: [(Hello,4),(Scala,3),(Hbase,2),(Kafka,1)]
// datas.flatMap(_.split(" ")).groupBy(x=>x).map(x=>(x._1,x._2.size)).foreach(println)
}
}
案例二word count
object $15_WordCountHight {
def main(args: Array[String]): Unit = {
val datas = List(("Hello Scala Spark World", 4), ("Hello Scala Spark", 3), ("Hello Scala", 2), ("Hello", 1))
//1、切割句子获得单词,赋予初始次数,压平
val words = datas.flatMap(x=>{
//x = ("Hello Scala Spark World", 4)
val arr = x._1.split(" ")
//Array(Hello,Scala,Spark,World)
val result = arr.map(y=>(y,x._2))
//Array( (Hello,4),(Scala,4),(Spark,4),(World,4) )
result
})
//List( (Hello,4),(Scala,4),(Spark,4),(World,4),(Hello,3),(Scala,3),(Spark,3),(Hello,2),(Scala,2),(Hello,1) )
//2、按照单词分组
val grouped = words.groupBy(_._1)
/**
* Map[
* Hello -> List( (Hello,4),(Hello,3),(Hello,2),(Hello,1) ),
* Scala -> List( (Scala,4),(Scala,3),(Scala,2)),
* Spark-> List( (Spark,4),(Spark,3)),
* World -> List( (World,4))
* ]
*/
//3、统计单词的总个数
val result = grouped.map(x=>{
//x = Hello -> List( (Hello,4),(Hello,3),(Hello,2),(Hello,1) )
//val num = x._2.map(_._2).sum
// (x._1,num)
val result = x._2.reduce((agg,curr)=>(agg._1,agg._2+curr._2 ))
result
})
//List[Hello->10,Scala->9,Spark->7,World->4]
//4、结果展示
result.foreach(println)
}
}
案例三
object $16_Home {
/**
* 1、求出哪些省份没有农产品市场
* 2、获取菜的种类最多的三个省份
* 3、获取每个省份菜的种类最多的三个农贸市场
*/
def main(args: Array[String]): Unit = {
val products = Source.fromFile("datas/product.txt","utf-8").getLines().toList
val allprovince = Source.fromFile("datas/allprovince.txt").getLines().toList
//m1(allprovince,products)
//m2(products)
m3(products)
}
/**
* 获取每个省份菜的种类最多的三个农贸市场
*/
def m3(products:List[String]) = {
//1、过滤非法数据
products.filter(_.split("\t").size==6)
//2、列裁剪- 选择 菜名、省份、农产品市场
.map(line=>{
val arr = line.split("\t")
(arr(4),arr(3),arr(0))
})
//3、去重
.distinct
//4、按照省份、农产品市场分组
.groupBy(x=> (x._1,x._2) )
/**
* Map(
* (湖南省,长沙市马王堆批发市场) -> List( (湖南省,长沙市马王堆批发市场,大白菜),(湖南省,长沙市马王堆批发市场,青椒),... )
* (湖南省,长沙市aa) -> List( (湖南省,长沙市aa,大白菜),(湖南省,长沙市aa,青椒),... )
* ....
* )
*/
//5、统计每个省份、每个农产品市场的菜的种类数
.map(x=>{
//x = (湖南省,长沙市马王堆批发市场) -> List( (湖南省,长沙市马王堆批发市场,大白菜),(湖南省,长沙市马王堆批发市场,青椒),... )
(x._1._1,x._1._2,x._2.size)
})
/**
* List(
* (湖南省,长沙市马王堆批发市场,10)
* (湖南省,长沙市aa,20)
* (湖北省,武汉市bb,30)
* ....
* )
*/
//6、按照省份分组
.groupBy(_._1)
/**
* Map(
* 湖南省 -> List( (湖南省,长沙市马王堆批发市场,10),(湖南省,长沙市aa,20),..)
* 湖北省 -> List( (湖北省,武汉市bb,30),... )
* ....
* )
*/
//7、对每个省份农产品种类数进行排序,取前三
.map(x=>{
//x = 湖南省 -> List( (湖南省,长沙市马王堆批发市场,10),(湖南省,长沙市aa,20),..)
(x._1,x._2.toList.sortBy(_._3).reverse.take(3))
})
//8、结果展示
.foreach(println)
}
/**
* 获取菜的种类最多的三个省份
*/
def m2(products:List[String]) = {
//1、过滤非法数据
products.filter(_.split("\t").length==6)
//2、列裁剪-选择菜名-省份
.map(line=>{
val arr = line.split("\t")
(arr(4),arr(0))
})
//List( ( 湖南省,大白菜),( 湖南省,大白菜),( 湖南省,青椒),...)
//3、去重【每个省份有多个农产品市场可能有多个同名的菜】
.distinct
//List( ( 湖南省,大白菜),( 湖南省,青椒),...)
//4、按照省份分组
.groupBy(_._1)
/**
* Map[
* 湖南省 -> List( ( 湖南省,大白菜),( 湖南省,青椒),...)
* 湖北省 -> List( ( 湖北省,大白菜),( 湖北省,青椒),...)
* ]
*/
//5、统计每个省份的菜的种类数量
.map(x=>{
//x = 湖南省 -> List( ( 湖南省,大白菜),( 湖南省,青椒),...)
(x._1,x._2.size)
})
//List( 湖南省->10,湖北省->5,..)
//6、排序
.toList
.sortBy(_._2)
//List(湖北省->5,湖南省->10,广东省->20,..)
//7、取前三
.reverse
.take(3)
//8、结果展示
.foreach(println)
}
/**
* 1、求出哪些省份没有农产品市场
*/
def m1(allprovince:List[String],products:List[String]) ={
//三要素: 过滤、去重、列裁剪
//1、过滤
val filterProduct = products.filter(line=>line.split("\t").length==6)
//2、获取农产品市场数据的省份
val productProvinces = filterProduct.map(line=> {
line.split("\t")(4)
})
//3、去重
val distincProvince = productProvinces.distinct
//4、将农产品数据省份与全国所有省份对比,得到哪些省份没有农产品市场【求差集】
val result = allprovince.diff(distincProvince)
//5、结果展示
result.foreach(println)
}
}
不可变队列
/**
* 队列的特点: 先进先出
* 创建方式: Queue[集合元素类型](初始元素,...)
* @param args
*/
def main(args: Array[String]): Unit = {
val queue = Queue[Int](10,2,4,1,6)
println(queue)
//添加元素
val queue2 = queue.+:(100)
val queue3 = queue.:+(200)
println(queue2)
println(queue3)
val queue4 = queue.++(List(9,8,7))
val queue5 = queue.++:(List(5,6,7))
println(queue4)
println(queue5)
val queue6 = queue.enqueue(1000)
println(queue6)
//删除元素
val dequeue: (Int, Queue[Int]) = queue.dequeue
println(dequeue)
val option = queue.dequeueOption
println(option)
//修改
val queue7 = queue.updated(1,20)
println(queue7)
}
可变队列
object $18_MutableQueue {
def main(args: Array[String]): Unit = {
//创建方式
val queue = mutable.Queue[Int](10,20,3,5,1)
println(queue)
//添加元素
val queue2 = queue.+:(30)
val queue3 = queue.:+(40)
queue.+=(50)
queue.+=:(60)
println(queue2)
println(queue3)
println(queue)
val queue4 = queue.++(List(1,2,3))
val queue5 = queue.++:(List(4,5,6))
println(queue4)
println(queue5)
queue.++=(List(7,8,9))
println(queue)
queue.enqueue(10,20,30,40)
println(queue)
//删除元素
println(queue.dequeue())
println(queue)
//修改
queue.update(0,20)
println(queue)
}
}
开启多线程
object $19_ParCollection {
def main(args: Array[String]): Unit = {
val list = List[Int](14,1,6,9,10,20,7,8)
list.foreach(x=>println(Thread.currentThread().getName))
println("8"*100)
list.par.foreach(x=>println(Thread.currentThread().getName))
}
}
模式匹配
object $01_MatchDefind {
/**
* 语法: 变量 match {
*
* case 值1 => {
* .....
* }
* case 值2 => {
* ...
* }
* .....
* }
*
* 模式匹配可以有返回值,返回值是符合条件的分支的{}的最后一个表达式的结果值
*
*/
def main(args: Array[String]): Unit = {
val word = StdIn.readLine("请输入一个单词:")
val result = word match {
case "hadoop" =>
println("输入的单词是hadoop")
10
case "spark" =>
println("输入的单词是spark")
20
case "flume" =>
println("输入的单词是flume")
30
//相当于switch的default
/* case x => {
println(s"其他单词${x}")
}*/
//如果变量不需要在=>右边使用可以用_代替
case _ => {
println(s"其他单词")
-1
}
}
println(result)
}
}
守卫
object $02_MatchIf {
/**
* 守卫语法:
* 变量 match {
* case 值 if(布尔表达式) => ...
* case 值 if(布尔表达式) => ...
* }
*/
def main(args: Array[String]): Unit = {
val line = StdIn.readLine("请输入一句话:")
line match {
case x if(x.contains("hadoop")) => println(s"输入的句子中包含hadoop")
case x if(x.contains("spark")) => println(s"输入的句子中包含spark")
case x if(x.contains("flume")) => println(s"输入的句子中包含flume")
case x => println("其他句子")
}
}
}
匹配值
object $03_MatchValue {
def main(args: Array[String]): Unit = {
val arr = Array("spark",1,2.0,false,30)
val index = Random.nextInt(arr.length)
val value:Any = arr(index)
println(value)
value match {
case 1 => println("........1")
case 2.0 => println("........2.0")
case "spark" => println("........spark")
case false => println("..........false")
case _ => println("其他")
}
}
}
匹配类型
/**
* 匹配语法: 变量 match{
* case 变量名:类型 => ...
* case 变量名:类型 => ..
* case _:类型 => .. //如果变量名不需要在=>右边使用可以用_代替
* ...
* }
*/
def main(args: Array[String]): Unit = {
val list:List[Any] = List(1,2.0,false,10,"spark")
val index = Random.nextInt(list.length)
val value = list(index)
println(value)
val result = value match {
case _:String => "输入的是字符串"
case x:Int => s"输入的是整数${x}"
case _:Double => "输入的是浮点型"
case _:Boolean => "输入的是布尔"
case _ => "其他"
}
println(result)
}
匹配数组
object $05_MatchArray {
def main(args: Array[String]): Unit = {
//val arr:Array[Any] = Array(4,1,10,2,7)
val arr:Array[Any] = Array("spark",1,2.0)
arr match {
//匹配数组只有一个元素
case Array(x) => println(s"数组只有一个元素${x}")
//匹配数组只有三个元素,匹配元素的类型
case Array(x:String,y:Int,z:Double) => println("匹配数组有三个元素,并且元素类型分别为String,Int,Double")
//匹配数组有三个元素
case Array(x,y,z) => println(s"数组有三个元素${x},${y},${z}")
//匹配数组至少有一个元素
case Array(_,_*) => println("数组至少有一个元素")
}
// int[] arr = new int[] {}
// object[] arr = new object[] {}
// String[] arr = new String[] {}
arr match {
//case x:Array[Int] => println("arr是Int数组")
case x:Array[Any] => println("arr是Any数组")
//case x:Array[String] => println("arr是String数组")
}
}
}
list匹配
object $06_MatchList {
def main(args: Array[String]): Unit = {
val list = List[Int](1,2,7,9,10)
//val list = List[Any]("spark",1,2.0)
//第一种匹配方式
list match {
//匹配List只有一个元素
case List(x) => println("List只有一个元素")
//匹配List有三个元素,以及匹配元素的类型
//case List(x:String,y:Int,z:Double) => println("list中有三个元素,并且元素类型为string,int,double")
//匹配List有三个元素
case List(x,_,z) => println("List有三个元素")
//匹配List至少有一个元素
case List(x,_*) => println("List至少有一个元素")
}
println("*"*100)
list match {
//匹配List只有一个元素
case x :: Nil => println("List只有一个元素")
//匹配List有三个元素,以及匹配元素的类型
//case (x:String) :: (y:Int) :: (z:Double) :: Nil => println("list中有三个元素,并且元素类型为string,int,double")
//匹配List有三个元素
case x :: _ :: z :: Nil => println("List有三个元素")
//匹配List至少有一个元素
case x :: y :: aaa => println(s"List至少有一个元素,${x} ${aaa}")
}
println("*"*100)
//泛型的特点: 泛型擦除,泛型只是编译器使用,用来规定集合里面的数据类型是啥,真正在编译的时候jvm虚拟机会将泛型擦掉
list match {
case x:List[String] => println("string list")
case x:List[Any] => println("any list")
case x:List[Int] => println("int list")
case _ => println("其他list")
}
}
}
匹配元组
object $07_MatchTuple {
def main(args: Array[String]): Unit = {
val t1 = ("zhangsan",20,"shenzhen")
//元组在匹配的时候,元组的元素的个数必须与匹配条件的元组的元素个数一致
val name = "zhangsan"
t1 match{
case (x:String,y:Int,z:String) => println(".........")
case (x,y,z) => println(s"${x} ${y} ")
// case (x,y) => println(s"${x} ${y} ${z}")
}
val schools = List[(String,(String,(String,Int)))](
("宝安中学",("大数据1班",("zhangsan",20))),
("宝安中学",("大数据1班",("lisi",20))),
("宝安中学",("大数据1班",("wangwu",20))),
("宝安中学",("大数据1班",("zhaoliu",20)))
)
//schools.map(x=> x._2._2._1 ).foreach(println)
schools.map(x=> {
x match {
case (schoolName,(className,(stuName,age))) => stuName
}
} ).foreach(println)
}
}
匹配样例类
object $08_MatchCaseClass {
//样例类
case class Person(name:String,var age:Int)
/* class Student(val name:String ,var age:Int)
object Student{
def apply(name:String,age:Int) = new Person(name,age)
}*/
case class School(name:String,clazz:Clazz)
case class Clazz(name:String,stu:Student)
case class Student(name:String,age:Int)
abstract class Sex
case object Man extends Sex
case object Woman extends Sex
def xx(sex:Sex): Unit ={
}
class Animal(val name:String,val age:Int)
object Animal{
def unapply(arg: Animal): Option[(String, Int)] = {
if(arg==null){
None
}else{
Some((arg.name,arg.age))
}
}
}
/**
* 样例类: case class 类名(val/var 属性名:属性类型,....)
* val修饰的属性不可变
* var修饰的属性可变
* val/var可以省略不写,如果省略默认就是val修饰的
* 样例创建对象: 类名(属性值,..)
*
* 样例对象: case object object名称
*样例对象一般作为枚举使用。
* @param args
*/
def main(args: Array[String]): Unit = {
//对象创建
val person = Person("zhangsan",20)
println(person)
println(person.name)
println(person.age)
//val student = Student("lisi",30)
//println(student.name)
val schools = List[School](
School("宝安中学",Clazz("大数据1班",Student("zhangsan",20))),
School("宝安中学",Clazz("大数据1班",Student("lisi",20))),
School("宝安中学",Clazz("大数据1班",Student("wangwu",20))),
School("宝安中学",Clazz("大数据1班",Student("zhaoliu",20)))
)
schools.map(x=>x.clazz.stu.name).foreach(println)
xx(Man)
person match {
case Person(x,y) => println(s"${x} ${y}")
}
val wangcai = new Animal("wangcai",5)
wangcai match {
case Animal(x,y) => println(s"${x} ${y}")
}
}
}
匹配参数
object $09_MatchParamDefind {
def main(args: Array[String]): Unit = {
val t1 = ("zhangsan",20,"shenzhen")
println(t1._1)
val (name,age,address) = ("zhangsan",20,"shenzhen")
println(name)
val x :: Nil = List(10)
println(x)
val Array(a,y,z) = Array(10,20,30)
println(a,y,z)
val name1:String = "zhangsan"
println(name)
val list = List[(String,Int)](("zhangsan",20),("lisi",30))
for((name,age)<- list){
println(name)
}
}
}
偏函数
/**
* 偏函数: 没有match关键字的模式匹配称之为偏函数
* 语法: val 函数名:PartialFunction[IN,OUT] = {
* case 条件1 =>...
* case 条件2 => ..
* ...
* }
* IN: 代表函数的参数类型
* OUT: 函数的返回值类型
* @param args
*/
def main(args: Array[String]): Unit = {
val func:PartialFunction[String,Int] = {
case "hadoop" =>
println("hadoop......")
10
case "spark" =>
println("spark..........")
20
case _ =>
println("其他.......")
-1
}
println(func("hadoop"))
val schools = List[(String,(String,(String,Int)))](
("宝安中学",("大数据1班",("zhangsan",20))),
("宝安中学",("大数据1班",("lisi",20))),
("宝安中学",("大数据1班",("wangwu",20))),
("宝安中学",("大数据1班",("zhaoliu",20)))
)
//schools.map(_._2._2._1).foreach(println(_))
/*schools.map(x=>{
x match {
case (schoolName,(className,(stuName,age))) =>stuName
}
}).foreach(println(_))*/
val getStuName:PartialFunction[(String,(String,(String,Int))),String] = {
case (schoolName,(className,(stuName,age))) => stuName
}
//schools.map(getStuName).foreach(println(_))
//偏函数使用的正确姿势
schools.map{
case (schoolName,(className,(stuName,age))) => stuName
}.foreach(println(_))
}
异常
object $01_Exception {
/**
* java中关于的异常的处理:
* 1、捕获异常: try{} catch{} finally{}
* try{
* ...
* }catch(Exception e){
* ..
* }finally{ --用于释放资源
* ..
* }
* 2、抛出异常: throw new ..Exception [必须在方法上throws Exception]
* scala中关于异常处理:
* 1、捕获异常:
* 1、try{} catch{} finally{} 【一般用于获取外部资源的时候使用】
* 2、Try(代码).getOrElse(代码执行失败返回的默认值)
* Success: 代表Try中包裹的代码执行成功,后续可以通过get方法取出代码的执行结果
* Filture: 代表Try中包裹的代码执行失败
* 2、抛出异常: throw new ..Exception [scala抛出异常不需要在方法后面通过throws Exception声明]
* @param args
*/
def main(args: Array[String]): Unit = {
//println(m1(10, 0))
println(m2(10,0))
val list = List[String](
"1 zhangsan 20 shenzhen",
"2 lisi beijing",
"3 lisi tianjin",
"4 zhaoliu 55 shenzhen"
)
//需求: 求年龄总和
list.map(line=>{
val age = Try(line.split(" ")(2).toInt).getOrElse(-1)
age
}).filter(_!= -1).foreach(println(_))
}
def m1(x:Int,y:Int) = {
if(y==0) throw new Exception("y=0")
x/y
}
def m2(x:Int,y:Int) = {
try{
x/y
}catch {
case e:Exception => println("y=0")
}
}
def jdbc() = {
var connection:Connection = null
var statement:PreparedStatement = null
try{
//1、获取连接
connection = DriverManager.getConnection("jdbc:mysql://hadoop102:3306/test")
//2、创建statement对象
statement = connection.prepareStatement("insert into person values(?,?,?)")
//3、封装参数
statement.setString(1,"zhangsan")
statement.setString(3,"shenzhen")
statement.setInt(2,20)
//4、执行
statement.executeUpdate()
}catch {
case e:Exception=>
}finally {
//5、关闭
if(statement!=null)
statement.close()
if(connection!=null)
connection.close()
}
}
}
either
object $02_Either {
def main(args: Array[String]): Unit = {
val either = m1(10,0)
either match {
case Left(result) =>
println(s"失败.....${result}")
case Right(result) =>
println(s"成功......${result}")
}
}
def m1(x:Int,y:Int) = {
try{
Right(x/y)
}catch {
case e:Exception => Left((y,e))
}
}
}
案例
object $03_Home {
def main(args: Array[String]): Unit = {
val datas = Source.fromFile("datas/aa","utf-8").getLines().toList
//1、切割(司机、区域、时间[转成时间戳])
datas.map(line=>{
//line="A 龙华区 宝安区 2020-07-15 10:05:10 2020-07-15 10:25:02"
val arr = line.split("\t")
val id = arr.head
val fromAddr = arr(1)
val toAddr = arr(2)
val fromTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(arr(3)).getTime
//LocalDateTime.parse(fromTime,DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
val toTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(arr(4)).getTime
(id,fromAddr,toAddr,fromTime,toTime)
})
//2、按照司机分组
.groupBy(_._1)
/**
* Map(
* A-> List(
* (A,龙华区,宝安区,2020-07-15 10:05:10,2020-07-15 10:25:02),
* (A,龙岗区,宝安区,2020-07-15 11:55:55,2020-07-15 12:12:23),
* (A,龙岗区,龙华区,2020-07-15 11:02:08,2020-07-15 11:17:15),
* (A,宝安区,龙岗区,2020-07-15 10:35:15,2020-07-15 10:40:50),
* (A,龙华区,龙岗区,2020-07-15 11:33:12,2020-07-15 11:45:35),
* (A,宝安区,龙岗区,2020-07-15 12:17:10,2020-07-15 12:33:21)
* )
* B-> List(
* (B,宝安区,福田区,2020-07-15 11:43:22 2020-07-15 11:55:45),
* (B,福田区,宝安区,2020-07-15 12:05:05 2020-07-15 12:22:33),
* (B,龙华区,龙岗区,2020-07-15 10:45:25 2020-07-15 10:50:00),
* (B,宝安区,龙岗区,2020-07-15 12:27:20 2020-07-15 12:43:31),
* (B,福田区,龙华区,2020-07-15 10:15:21 2020-07-15 10:35:12),
* (B,龙岗区,宝安区,2020-07-15 11:12:18 2020-07-15 11:27:25)
* )
* )
*/
.toList
//3、对每个司机的数据按照上车/下车时间排序
.flatMap(x=>{
//x= A-> List(
// (A,龙华区,宝安区,2020-07-15 10:05:10,2020-07-15 10:25:02),
// (A,龙岗区,宝安区,2020-07-15 11:55:55,2020-07-15 12:12:23),
// (A,龙岗区,龙华区,2020-07-15 11:02:08,2020-07-15 11:17:15),
// (A,宝安区,龙岗区,2020-07-15 10:35:15,2020-07-15 10:40:50),
// (A,龙华区,龙岗区,2020-07-15 11:33:12,2020-07-15 11:45:35),
// (A,宝安区,龙岗区,2020-07-15 12:17:10,2020-07-15 12:33:21)
// )
val list = x._2.sortBy(_._4)
// List(
// (A,龙华区,宝安区,2020-07-15 10:05:10,2020-07-15 10:25:02),
// (A,宝安区,龙岗区,2020-07-15 10:35:15,2020-07-15 10:40:50),
// (A,龙岗区,龙华区,2020-07-15 11:02:08,2020-07-15 11:17:15),
// (A,龙华区,龙岗区,2020-07-15 11:33:12,2020-07-15 11:45:35),
// (A,龙岗区,宝安区,2020-07-15 11:55:55,2020-07-15 12:12:23),
// (A,宝安区,龙岗区,2020-07-15 12:17:10,2020-07-15 12:33:21)
//)
val slidingList = list.sliding(2)
/**
* List(
* List((A,龙华区,宝安区,2020-07-15 10:05:10,2020-07-15 10:25:02),(A,宝安区,龙岗区,2020-07-15 10:35:15,2020-07-15 10:40:50)),
* List((A,宝安区,龙岗区,2020-07-15 10:35:15,2020-07-15 10:40:50),(A,龙岗区,龙华区,2020-07-15 11:02:08,2020-07-15 11:17:15)),
* List((A,龙岗区,龙华区,2020-07-15 11:02:08,2020-07-15 11:17:15),(A,龙华区,龙岗区,2020-07-15 11:33:12,2020-07-15 11:45:35)),
* List((A,龙华区,龙岗区,2020-07-15 11:33:12,2020-07-15 11:45:35),(A,龙岗区,宝安区,2020-07-15 11:55:55,2020-07-15 12:12:23)),
* List((A,龙岗区,宝安区,2020-07-15 11:55:55,2020-07-15 12:12:23),(A,宝安区,龙岗区,2020-07-15 12:17:10,2020-07-15 12:33:21)),
*
* )
*/
//4、计算每个司机每次的等客时间
val result = slidingList.map(y=>{
//y = List((A,龙华区,宝安区,2020-07-15 10:05:10,2020-07-15 10:25:02),(A,宝安区,龙岗区,2020-07-15 10:35:15,2020-07-15 10:40:50)),
//等客区域
val region = y.head._3
//等客时间 = 下一次的上车时间 - 上一次下车时间
val duration = y.last._4 - y.head._5
(region,duration)
})
result
})
//List( (宝安区,10),(龙岗区,22),(龙华区,16),(龙岗区,10),(宝安区,5) ,(龙华区,10),(龙岗区,22),(宝安区,16),(福田区,10),(宝安区,5))
//6、按照区域分组
.groupBy(_._1)
/**
* Map(
* 宝安区-> List((宝安区,10),(宝安区,5),(宝安区,16),(宝安区,5))
* ....
* )
*/
//7、计算平均等客时间
.map(x=>{
//x = 宝安区-> List((宝安区,10),(宝安区,5),(宝安区,16),(宝安区,5))
val time = x._2.map(_._2).sum
val count = x._2.size
(x._1,time/count/1000)
})
//8、结果展示
.foreach(println(_))
}
}
隐式转换
import java.io.File
import scala.io.{BufferedSource, Source}
object xx{
implicit def fileToSourceBufferd(file:File):BufferedSource = {
Source.fromFile(file,"utf-8")
}
implicit def doubeToInt1(x:Double):Int = x.toInt
implicit def doubeToInt2(x:Double):Int = x.toInt + 10
}
object $01_ImplicitMethod{
/**
* 隐式方法: 悄悄将一个类型转成另一个类型
* 语法: implicit def 方法名(变量名:待转换类型): 目标类型 = {..}
*隐式转换方法使用时机:
* 1、当前类型与目标类型不一致的时候,会自动调用隐式方法
* 2、当对象使用了不属于自身的属性/方法/函数的时候,会自动调用隐式方法
*隐式转换的解析:
* 当需要使用隐式转换的时候,后首先从当前的作用域中查找是否有符合条件的隐式转换
* 如果说隐式转换不在当前作用域,需要进行导入之后再使用:
* 1、如果隐式转换定义在Object中,导入的时候使用: import 包名.object名称.隐式转换方法名
* 2、如果隐式转换定义在class中,导入的时候使用:
* 1、创建对象
* 2、对象名.隐式转换方法名
* @param args
*/
def main(args: Array[String]): Unit = {
// 1、当前类型与目标类型不一致的时候,会自动调用隐式方法
//val abc = new xx
import xx.doubeToInt1
val a:Int = 2.0
println(a)
val file = new File("d:/pmt.json")
//2、当对象使用了不属于自身的属性/方法/函数的时候,会自动调用隐式方法
import xx.fileToSourceBufferd
file.getLines()
}
}
隐式转换参数
object AA{
implicit val y:Int = 10
implicit val a:Int = 100
}
object $02_ImplicitParam {
/**
* 隐式转换参数的语法:
* 1、通过implicit val 变量名:类型 = 值
* 2、def 方法名(..)(implicit 变量名:类型)
* 如果有多个隐式转换参数/方法都符合要求,需要明确通过import 包名.隐式参数名/方法名的方式指定使用哪个隐式转换参数/方法
* @param args
*/
def main(args: Array[String]): Unit = {
import AA.a
println(m1(20))
}
def m1(x:Int)(implicit y:Int) = x+y
隐式转换类
object $03_ImplicitClass {
class Person(val name:String,val age:Int)
implicit class MaxMin(p:Person){
def max(p1:Person) = {
if(p.age<p1.age) p1
else p
}
}
/**
* scala隐式转换类在2.10版本之后才有
* 语法: implicit class 类名(属性名: 待转换的类型) {
* ...
* }
* @param args
*/
def main(args: Array[String]): Unit = {
val person1 = new Person("zhagnsan",20)
val person2 = new Person("lisi",30)
person1.max(person2)
}
//implicit def personToMaxMin(p:Person ):MaxMin = new MaxMin(p)
}
泛型方法
/**
* 泛型主要用于方法与类
* 泛型方法的定义语法: def 方法名[T,U](x:T):U = {..}
*/
def main(args: Array[String]): Unit = {
println(m1[Int](Array[Int](1, 2, 3)))
}
def m1[T](x:Array[T]):Int = {
x.length
}
泛型类
object $02_GenericClass {
class Person[T,U](var name:T,var age:U) {
def setName(name:T) = this.name=name
def getName():T = this.name
}
/**
* 泛型类的定义语法: class 类名[T,U](val/var 属性名:T,..) {
*
* def 方法名(参数名:U):返回值类型 = {..}
* }
* @param args
*/
def main(args: Array[String]): Unit = {
val person = new Person[String,Int]("zhangsan",20)
person.setName("lisi")
println(person.getName())
}
}
泛型上下限
/**
* 上下限:
* 上限【代表传入的泛型必须是指定类型或者是其子类】: T <: 指定类型
* 下限 【代表传入的类型必须是指定类型或者是其父类】 : T >: 指定类型
* @param args
*/
def main(args: Array[String]): Unit = {
//m1(new BigBigDog)
val big:Any = new BigBigDog
m2(1)
}
class Animal
class Dog extends Animal
class BigDog extends Dog
class BigBigDog extends BigDog
def m1[T<:Dog](x:T) = {
println(x)
}
def m2[U>:BigDog](x:U) = {
println(x)
}
泛型 非变、协变、逆变
object $04_GenericChange {
class Parent
class Sub1 extends Parent
class Sub2 extends Sub1
//class AA[T]
//class AA[+T]
class AA[-T]
/**
* 非变: 泛型有父子关系,但是泛型对象没有任何关系 T
* 协变: 泛型有父子关系,泛型对象继承了泛型的父子关系 +T
* 逆变: 泛型有父子关系,泛型对象颠倒了泛型的父子关系 -T
* @param args
*/
def main(args: Array[String]): Unit = {
var list1 = List[B](new B,new B)
var list2 = List[B1](new B1,new B1)
list1 = list2
println(list1)
//非变
//var aa1 = new AA[Parent]
//var aa2 = new AA[Sub1]
//aa1 = aa2
//协变
//var aa1 = new AA[Parent]
//var aa2 = new AA[Sub1]
//aa1 = aa2
//println(aa1)
//逆变
var aa1 = new AA[Parent]
var aa2 = new AA[Sub1]
aa2 = aa1
println(aa2)
}
class B
class B1 extends B
}
泛型上下文
/**
* 泛型上下文语法: def 方法名[T:类型](参数名:T) = {
* val 变量名 = implicitly[类型[T]]
* ....
* }
* @param args
*/
def main(args: Array[String]): Unit = {
implicit val p = new Person[String]
f[String]("zhangsan")
f[String]("lisi")
}
class Person[U]{
var field:U = _
def printHello = println("hello.....")
def setField(field:U) = this.field = field
}
def f[A](a:A)(implicit person:Person[A])= {
person.setField(a)
person.printHello
}
def f1[A:Person](a:A) = {
val person = implicitly[Person[A]]
person.setField(a)
person.printHello
}
案例分析
需求: 统计每个用户一小时内的最大登录次数
user_id,login_time
a,2020-07-11 10:51:12
a,2020-07-11 11:05:00
a,2020-07-11 11:15:20
a,2020-07-11 11:25:05
a,2020-07-11 11:45:00
a,2020-07-11 11:55:36
a,2020-07-11 11:59:56
a,2020-07-11 12:35:12
a,2020-07-11 12:58:59
b,2020-07-11 14:51:12
b,2020-07-11 14:05:00
b,2020-07-11 15:15:20
b,2020-07-11 15:25:05
b,2020-07-11 16:45:00
b,2020-07-11 16:55:36
b,2020-07-11 16:59:56
b,2020-07-11 17:35:12
b,2020-07-11 17:58:59
import java.text.SimpleDateFormat
import scala.io.Source
object $01_Home {
/**
* 需求: 统计每个用户一小时内的最大登录次数
* @param args
*/
def main(args: Array[String]): Unit = {
//1、读取数据
val datas = Source.fromFile("datas/datas.txt","utf-8").getLines().toList
//2、切割数据,转换时间
val mapDatas = datas.map(line=>{
val arr = line.split(",")
val userID = arr.head
val time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(arr.last).getTime
(userID,time)
})
//3、遍历数据,根据遍历的每条数据筛选哪些数据与该数据处于一个小时
mapDatas.map(x=>{
//x = (a,2020-07-11 10:51:12)
//4、统计每个时间对应的登录次数
val num = mapDatas.filter(y=>y._1 == x._1 && y._2>=x._2 && y._2<=x._2+3600000).size
(x._1,num)
})
//5、按照用户进行分组
.groupBy(_._1)
/**
* Map(
* a-> List( (a,5),(a,6),(a,4),..)
* b-> List( (b,4),..)
* )
*/
//6、统计最大登录次数
.map(x=>{
//x=a-> List( (a,5),(a,6),(a,4),..)
x._2.maxBy(_._2)
})
//7、结果展示
.foreach(println(_))
}
}
案例分析二
val list = List[(String,String,String)](
("1001","2020-09-10 10:21:21","home.html"),
("1001","2020-09-10 10:28:10","good_list.html"),
("1001","2020-09-10 10:35:05","good_detail.html"),
("1001","2020-09-10 10:42:55","cart.html"),
("1001","2020-09-10 11:35:21","home.html"),
("1001","2020-09-10 11:36:10","cart.html"),
("1001","2020-09-10 11:38:12","trade.html"),
("1001","2020-09-10 11:40:00","payment.html"),
("1002","2020-09-10 09:40:00","home.html"),
("1002","2020-09-10 09:41:00","mine.html"),
("1002","2020-09-10 09:42:00","favor.html"),
("1003","2020-09-10 13:10:00","home.html"),
("1003","2020-09-10 13:15:00","search.html")
)
//需求: 分析用户每次会话的行为轨迹
import java.text.SimpleDateFormat
import java.util.UUID
case class UserAnasisy(var sessionid:String,userid:String,time:Long,page:String)
object $02_Home {
def main(args: Array[String]): Unit = {
val list = List[(String,String,String)](
("1001","2020-09-10 10:21:21","home.html"),
("1001","2020-09-10 10:28:10","good_list.html"),
("1001","2020-09-10 10:35:05","good_detail.html"),
("1001","2020-09-10 10:42:55","cart.html"),
("1001","2020-09-10 11:35:21","home.html"),
("1001","2020-09-10 11:36:10","cart.html"),
("1001","2020-09-10 11:38:12","trade.html"),
("1001","2020-09-10 11:40:00","payment.html"),
("1002","2020-09-10 09:40:00","home.html"),
("1002","2020-09-10 09:41:00","mine.html"),
("1002","2020-09-10 09:42:00","favor.html"),
("1003","2020-09-10 13:10:00","home.html"),
("1003","2020-09-10 13:15:00","search.html")
)
// 每条数据都给一个唯一标识,进行数据转换
list.map(x=>{
val sessionid = UUID.randomUUID().toString
val time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(x._2).getTime
UserAnasisy(sessionid,x._1,time,x._3)
})
//分组
.groupBy(_.userid)
/**
* Map(
* 1001-> List(UserAnasisy("1","1001","2020-09-10 10:21:21","home.html"),UserAnasisy("2","1001","2020-09-10 10:28:10","good_list.html"),UserAnasisy...)
* 1002-> List(...)
* )
*/
//按照时间排序
.flatMap(x=>{
val sortedUser = x._2.sortBy(_.time)
//窗口
val slidingList = sortedUser.sliding(2)
/**
* List(
* List(UserAnasisy("1","1001","2020-09-10 10:21:21","home.html"),UserAnasisy("2","1001","2020-09-10 10:28:10","good_list.html"))
* List(UserAnasisy("2","1001","2020-09-10 10:28:10","good_list.html"),UserAnasisy ("3","1001","2020-09-10 10:35:05","good_detail.html"))
* ...
* )
*/
slidingList.foreach(y=>{
//y = List(UserAnasisy("1","1001","2020-09-10 10:21:21","home.html"),UserAnasisy("2","1001","2020-09-10 10:28:10","good_list.html"))
//判断上一次与下一次是否在30分钟内,如果在30分钟内就是属于同一次会话
if(y.last.time - y.head.time < 30*60*1000) {
y.last.sessionid = y.head.sessionid
}
})
x._2
})
//结果展示
.foreach(println(_))
}
}
案例分析三