第一章.函数式编程
面向对象编程:
- 解决问题,分解对象,行为,属性,然后通过对象的关系以及行为的调用来解决问题
- 对象: 用户
- 行为: 登录,连接Jdbc,读取数据库
- 属性: 用户名,密码
- Scala语言是一个完全面向对象编程语言,万物皆对象
函数式编程:
- 解决问题时,将问题分解成一个一个的步骤,将每个步骤进行封装(函数),通过调用这些封装好的步骤,解决问题
- 例如: 请求->用户名,密码->连接jdbc->读取数据库
在Scala中函数式编程和面向对象编程融合在一起了
1.方法定义语法
package com.atguigu.chapter05object $01_MethodDefined {/*** 方法定义语法: def 方法名(参数名:参数类型,....):返回值类型={方法体}*/def main(args:Array[String]): Unit={println(add(10,20))}def add(x:Int,y:Int):Int={x+y}}
2.方法简化的原则
package com.atguigu.chapter05object $02_MethodSample {/*** 方法简化的原则:* 1.如果方法使用方法体的块表达式的结果值作为方法的返回值,此时定义方法的时候方法的返回值类型可以省略* 注意:如果方法体中有return关键字,方法的返回值类型必须定义* 2.如果方法体只有一行语句,那么方法体的{}可以忽略* 3.如果方法不需要返回值,那么定义方法的时候=可以忽略 [=与{}不能同时忽略]*/def main(args:Array[String]):Unit={println(add2(10,20))println(add3(10,20))printMsg2("hello")//1.如果定义方法的时候没有(),那么在调用方法的时候()也不能带上hello2//2.如果定义方法的时候有(),那么在调用方法的时候()可有可无hello()hello}//标准定义形式def add(x:Int,y:Int):Int={return x + y}//1.如果方法使用方法体的块表达式的结果值作为方法的返回值,此时定义方法的时候,方法的返回值类型可以忽略def add2(x:Int,y:Int)={x + y}//2.如果方法体只有一行语句,那么方法体的{}可以忽略def add3(x:Int,y:Int) = x + y//标准形式def printMsg(msg:String):Unit={println(s"msg=${msg}")}//3.如果方法不需要返回值,那么定义方法的时候=可以忽略[=与{}不能同时忽略]def printMsg2(msg:String){println(s"msg=${msg}")}//标准形式def hello():Unit={println("hello...........")}//4.如果方法不需要参数,那么定义方法的时候()可以忽略def hello2{println("hello2...........")}}
3.方法参数
object $03_MethodParam {/*** scala方法的参数* 1.默认值参数,在调用方法的时候有默认值的参数可以不用传参数[默认值参数一般放在参数列表最后面]* 语法: def 方法名(参数名:类型[默认值],.....):返回值类型 = {方法体}* 2.带名参数:在调用方法的时候指定将参数值传给哪个参数* 3.可变参数:在调用方法的时候传递的参数的个数不固定* 语法: def 方法名(参数名:类型,...,参数名:类型*):返回值类型={方法体}* scala可变参数不能直接传递集合,如果想要将集合所有元素传递给可变参数,可以通过 集合名:_*的方式传递*/def main(args:Array[String]):Unit ={println(add(10))//带名参数println(add(x=4,y=6))val arr = Array[Int](10,20,30,40)println(sum(10,20,arr:_*))}//默认值参数def add(x:Int,y:Int=30) = x + y//可变参数def sum(x:Int,y:Int,z:Int*) = x + y + z.sum}
需求: 统计前七天的用户注册数
object demo{//需求:统计前七天的用户注册数def main(args: Array[String]): Unit = {val paths = getPaths(7, "/user/hive/warehouse/user_info")println(paths)println("----------------------------------")readPaths(paths)}def getPaths(n:Int,pathPrefix:String)={//获取当前日期val currentDate = LocalDateTime.now()for(i<-1 to n) yield{//日期加减法val time = currentDate.plusDays(-i)//格式化时间val timeStr = time.format(DateTimeFormatter.ofPattern("yyyyMMdd"))s"${pathPrefix}/${timeStr}"}}def readPaths(paths:IndexedSeq[String]):Unit={for (path <- paths) {println(path)}}}
4.函数定义语法
package com.atguigu.chapter05object $04_FunctionDefiend {/*** 方法就是函数,函数也是对象* 函数的定义语法: val 函数名 = (参数名:参数类型,...) => {函数体}* 函数的简化:如果函数体中只有一行语句,那么函数体{}可以忽略* 函数是对象,函数的类型:(参数类型,....)=>返回值类型**/def main(args: Array[String]): Unit = {println(func(10,20))println(func.apply(10,20))val name2 = nameval func3 = funchello()println(hello)println(func3(30,40))}val func=(x:Int,y:Int) => {x + y}val name:String = "zhangsan"val hello=()=>{println("...........")}val func2 = new Function2[Int,Int,Int]{override def apply(v1:Int,v2:Int):Int=v1+v2}}
5.方法与函数的区别
package com.atguigu.chapter05object $05_MethodAndFunction {/*** 方法与函数的区别* 1.方法定义在类中的时候可以重载,函数是对象,函数名就是对象的引用,所以不能重载* 2.方法存储在方法区中,函数是对象存储在堆中* 方法和函数的关系* 1.方法名可以转成函数,可以通过 方法名 _ 的方式转成函数* 2.方法如果定义在方法中就是函数,不能重载的*/def main(args: Array[String]): Unit = {println(func(10,20))println(add(10,20,30))//方法转函数val func2 = add _println(func2(10,20,30))}val func = (x:Int,y:Int)=>x + y// func = (x:Int,y:Int,z:Int)=>x + y + z//def add(x:Int,y:Int)= x+ydef add(x:Int,y:Int,z:Int) = x + y + z}
6.高阶函数的定义
package com.atguigu.chapter05object $06_HIghFunction {/*** 高阶函数:以函数作为参数或者返回值的方法/函数称之为高阶函数**/def main(args: Array[String]): Unit = {val func =(x:Int,y:Int)=>{x + y}println(add(10,20,func))}//高阶函数def add(x:Int,y:Int,func:(Int,Int)=>Int)={func(x,y)}}
7.高阶函数的简化
package com.atguigu.chapter05object $07_HightFunctionSample {/*** 高阶函数的简化:* 1.可以直接将函数的值传给参数* 2.函数的参数类型可以省略* 3.如果函数的参数在函数体中只使用了一次可以用_代替* 注意:以下情况下不能以_代替* 1.函数体中参数的使用顺序与定义顺序不一致的时候不能用_代替[第N个下划线代表函数第N个参数]<针对函数有多个参数的情况>* 2.如果函数只有一个参数,在函数体中没有做任何操作,直接返回参数本身,此时不能用_代替<针对函数只有一个参数的情况>* 3.如果函数的参数体中有嵌套,函数的参数在嵌套中以表达式存在,此时不能用_简化* 4.如果函数只有一个参数,函数的参数列表的()可以省略*/def main(args: Array[String]): Unit = {val func = (x:Int,y:Int) => x * yprintln(add(10,20,func))//1.可以直接将函数的值传给参数println(add(10,20,(x:Int,y:Int)=>x * y))//2.函数的参数类型可以省略println(add(10,20,(x,y)=>x * y))//3.如果函数的参数在函数体中只使用了一次可以用_代替println(add(10,20,_ * _))//println(add(10,20,(x,y)=>y-x))//1.函数体中参数的使用顺序与定义顺序不一致时不能用_代替//println(add(10,20,_-_))//2.如果函数只有一个参数,在函数体中没有做任何操作,直接返回函数本身,此时不能用_代替println(add2(10,(x:Int)=>x))//println(add2(10,_))//3.如果函数体中有嵌套,函数的参数在嵌套中以表达式形式存在,此时不能用_代替println(add2(10,(x:Int)=>(x+1)*10))//println(add2(10,(_+1)*10))//4.如果函数只有一个参数,函数的参数列表的()可以省略println(add2(10,x=>(x+1)*10))}def add(x:Int,y:Int,func:(Int,Int)=>Int)={func(x,y)}def add2(x:Int,func:Int=>Int) =func(x)}
8.匿名函数
package com.atguigu.chapter05object $08_NoNameFunction {/*** 匿名函数:没有函数名的函数称之为匿名函数* 匿名函数一般不单独使用,一般作为高阶函数的参数值传递**/def main(args: Array[String]): Unit = {val func = (x:Int) => x+10println(func(20))println(add(100,func))//匿名函数一般不单独使用,一般作为高阶函数的参数值传递println(add(100,_+10))}def add(x:Int,func:Int=>Int)=func(x)}
9.递归
package com.atguigu.chapter05object $09_Recursion {/*** 递归:自己调用自己* 递归必须满足两个条件:* 1.必须要有退出条件* 2.必须定义返回值类型*/def main(args: Array[String]): Unit = {println(func(5))println(m1(5))}val func:Int =>Int=(n:Int)=>{if(n==1) 1else n * func(n-1)}/*val func=(n:Int) =>{if(n==1) 1else n * func(n-1)}*/def m1(n:Int):Int={//必须有退出条件if(n==1) 1else n * m1(n-1)}}
10.柯里化
package com.atguigu.chapter05object $10_Currying {/*** 柯里化:有多个参数列表的方法称之为柯里化*/def main(args: Array[String]): Unit = {println(m1(10,20)(30)(40))println(m2(10,20,30,40))}/*** 柯里化*/def m1(x:Int,y:Int)(z:Int)(a:Int)=x+y+z+adef m2(x:Int,y:Int,z:Int,a:Int)=x+y+z+a}
11.闭包
package com.atguigu.chapter05object $11_ClosePackage {/*** 闭包:函数体中使用了外部变量的函数称之为闭包*/def main(args: Array[String]): Unit = {println(func(10))}val y =20//闭包函数val func =(x:Int)=>{x + y}}
12.惰性求值
package com.atguigu.chapter05object $12_Lazy {/*** 惰性求值:只有变量在真正使用的时候才会初始化* 语法:lazy val 变量名:类型 = 值*/def main(args: Array[String]): Unit = {val name = "zhangsan"println(s"name=${name}")lazy val age =20println(s"age=${age}")}}
13.控制抽象
package com.atguigu.chapter05object $18_ControlAbstract {/*** 控制抽象:* 语法: => 返回值类型* 控制抽象不能单独使用,只能作为方法的参数类型存在* 控制抽象其实就是一个块表达式,后续可以当做函数调用,只是在调用控制抽象时不能带上()*/def main(args: Array[String]): Unit = {val a ={println("---------------")10+20}m1(a)m1(a)m1(a)val func=()=>{println("=====================")10+20}m2(func)m2(func)m2(func)m3({println("***************")10+20})}def m1(x:Int) =x * xdef m2(func:()=>Int)= func() * func()def m3(func: =>Int)={funcfuncfunc}}
第二章.练习
1.练习一
需求:根据指定规则对数组中的每个元素操作数据: Array[String]("hello","spark","java","hadoop")规则: 获取每个元素的长度 [可变]结果: Array[Int](5,5,4,6)
package com.atguigu.chapter05object $13_HomeWork01 {/** 需求: 根据指定规则对数组中的每个元素操作- 数据: Array[String]("hello","spark","java","hadoop")- 规则: 获取每个元素的长度 [可变]- 结果: Array[Int](5,5,4,6)* */def main(args: Array[String]): Unit = {val data = Array[String]("hello","spark","java","hadoop")val func = (x:String) =>x.lengthval arr = map(data,func)println(arr.toList)}def map(data:Array[String],func:String => Any)={for(element<-data) yield{func(element)}}}
2.练习二
根据指定规则对数组进行过滤数据: Array[Int](1,4,3,7,6,10,9)规则: 保留偶数数据 [可变]结果: Array[Int](4,6,10)
package com.atguigu.chapter05object $14_HomeWork02 {/*** 根据指定规则对数组进行过滤数据: Array[Int](1,4,3,7,6,10,9)规则: 保留偶数数据 [可变]结果: Array[Int](4,6,10)*/def main(args: Array[String]): Unit = {val data = Array[Int](1, 4, 3, 7, 6, 10, 9)val func = (data:Array[Int]) => {val arr = data.filter(x => x%2==0)arr.toList}val result = map(data,func)println(result)}def map(data:Array[Int],func:Array[Int]=>Any)={func(data)}}
3.练习三
根据指定规则对数组所有元素进行聚合数据: Array[Int](1,4,3,7,6,10,9)规则: 求和 [可变]结果: 40
package com.atguigu.chapter05object $15_HomeWork03 {/*** 根据指定规则对数组所有元素进行聚合数据: Array[Int](1,4,3,7,6,10,9)规则: 求和 [可变]结果: 40*/def main(args: Array[String]): Unit = {val sum =0val data= Array[Int](1,4,3,7,6,10,9)val func=(data:Array[Int])=>data.sumval result = map(data,func)println(result)}def map(data:Array[Int],func:Array[Int]=>Int)={func(data)}}
4.练习四
根据指定规则对数组中的元素进行分组数据: Array[String]("zhangsan man shenzhen","lisi woman beijing","zhaoliu man beijing")规则: 按照性别分组 [可变]结果: Map( man-> List( "zhangsan man shenzhen", "zhaoliu man beijing") , woman -> List( "lisi woman beijing" ) )
package com.atguigu.chapter05import java.utilobject $16_HomeWork04 {/*** 根据指定规则对数组中的元素进行分组数据: Array[String]("zhangsan man shenzhen","lisi woman beijing","zhaoliu man beijing")规则: 按照性别分组 [可变]结果: Map( man-> List( "zhangsan man shenzhen", "zhaoliu man beijing") , woman -> List( "lisi woman beijing" ) )*/def main(args: Array[String]): Unit = {val data = Array[String]( "zhangsan man shenzhen","lisi woman beijing","zhaoliu man beijing")val func =(x:String)=>x.split(" ")(1)println(groupBy(data, func))}def groupBy(data:Array[String],func:String=>Any)={//定义一个容器装载分组的结果val map = new util.HashMap[Any,util.List[String]]()//遍历for(element<-data){//得到分组的keyval key = func(element)//判断key是否存在,如果存在则直接将当前元素添加到key对应的list中if(map.containsKey(key)){val list = map.get(key)list.add(element)}if(!map.containsKey(key)){val list = new util.ArrayList[String]()list.add(element)map.put(key,list)}}map}}
5.练习五
根据指定规则获取数组中的最大值的信息数据: Array[String]("zhangsan 20 1500","lisi 35 2000","zhaoliu 18 4500")规则: 获取年龄最大的人的信息 [可变]结果: "lisi 35 2000"
package com.atguigu.chapter05object $17_HomeWork05 {/*根据指定规则获取数组中的最大值的信息数据: Array[String]("zhangsan 20 1500","lisi 35 2000","zhaoliu 18 4500")规则: 获取年龄最大的人的信息 [可变]结果: "lisi 35 2000"*/def main(args: Array[String]): Unit = {val data = Array[String]("zhangsan 20 1500", "lisi 35 2000", "zhaoliu 18 4500")val func = (x: String) => {x.split(" ")(1).toInt}println(maxBy(data, func))}def maxBy(data:Array[String],func:String=>Int)={//定义中间变量var tmp = func(data(0))var result:String = nullfor (elem <- data) {val key = func(elem)if(key >= tmp){tmp = keyresult =elem}}result}}
