高阶函数
函数的参数是函数的函数或者方法
函数的返回值是函数的函数或者方法
函数的参数和返回值都是函数的函数或者方法
使用高阶函数的一个原因是减少冗余的代码。比方说需要写几个方法以通过不同方式来提升员工工资,若不使用高阶函数,代码可能像这样:
object SalaryRaiser {
def smallPromotion(salaries: List[Double]): List[Double] =
salaries.map(salary => salary * 1.1)
def greatPromotion(salaries: List[Double]): List[Double] =
salaries.map(salary => salary * math.log(salary))
def hugePromotion(salaries: List[Double]): List[Double] =
salaries.map(salary => salary * salary)
}
有了高阶函数以后,可以使用在函数中传入逻辑性的代码(函数)即可 , 减少了代码的冗余性 !
函数或者方法的参数是函数
class HighFunction{
//在方法的参数中定义一个函数,f:String=>Int
def m(s:String,f:String=>Int)={
//使用该方法的第一个参数自己调用自己的函数
f(s)
}
}
object HighFunction {
def apply(): HighFunction = new HighFunction()
def main(args: Array[String]): Unit = {
//传入参数,并自定义函数的实现方式(字符串转为Int类型)
val i: Int = HighFunction().m("123", x => x.toInt)
println(i) //123
}
函数的返回值是函数
class HighFunction{
//定义一个空参的方法,设置该方法的返回值为一个函数
def m2(): String => Int = {
f:String=>f.toInt
}
}
object HighFunction {
def apply(): HighFunction = new HighFunction()
def main(args: Array[String]): Unit = {
//使用方法一:先调用m2,然后m2会返回一个函数mf,我们再调用mf("123")
val mf: String => Int = HighFunction().m2
val i1: Int = mf("123")
//使用方法二:在调用m2方法的时候,直接传入一个("2312"),该参数就会自动调用m2里面的函数,然后返回实现该函数的功能后的值
val i2: Int = HighFunction().m2("2312")
}
}
def urlBuilder(ssl: Boolean, domainName: String): (String, String) => String = {
val schema = if (ssl) "https://" else "http://"
(endpoint: String, query: String) => s"$schema$domainName/$endpoint?$query"
}
val domainName = "www.example.com"
def getURL = urlBuilder(ssl=true, domainName)
val endpoint = "users"
val query = "id=1"
val url = getURL(endpoint, query) // "https://www.example.com/users?id=1": String
偏函数
偏函数是一个特质 ,是专门用来处理一种类型数据用的
例如 将集合中的所有的Int类型的数据都加上1
// 方式一 过滤器形式
val list = List(1, 2, 3, 4, "hello")
val res: List[Int] = list.filter(x => x.isInstanceOf[Int]).map(x => x.asInstanceOf[Int] + 1)
res.foreach(println)
// 方式二 匹配模式
val res2: List[Any] = list.map(x => x match {
case x: Int => x + 1
case _ =>
})
res2.filter(x => x.isInstanceOf[Int]).foreach(println)
// 方式三 使用偏函数 泛型1 输入的数据类型 泛型2 要处理的数据类型
val pp = new PartialFunction[Any,Int] {
// 返回true
override def isDefinedAt(x: Any) = {
x.isInstanceOf[Int]
}
// 执行下一个方法
override def apply(v1: Any) = {
v1.asInstanceOf[Int]+1
}
}
// list.map(pp).foreach(println)
list.collect(pp).foreach(println)
偏函数的执行流程
偏函数的执行流程
1 遍历list中的每个元素
2 调用 val e = if (isDefinedAt) {apply}
3 每得到一个e 就会将e存储在一个新的集合中 返回
使用偏函数就不要使用map方法了
偏函数总结
1)使用构建特质的实现类(使用的方式是PartialFunction的匿名子类)
2)PartialFunction 是个特质(看源码)
3)构建偏函数时,参数形式 [Any, Int]是泛型,第一个表示参数类型,第二个表示返回参数
4)当使用偏函数时,会遍历集合的所有元素,编译器执行流程时先执行isDefinedAt()如果为true ,就会执行 apply, 构建一个新的Int 对象返回
5)执行isDefinedAt() 为false 就过滤掉这个元素,即不构建新的Int对象.
6)map函数不支持偏函数,因为map底层的机制就是所有循环遍历,无法过滤处理原来集合的元素
7)collect函数支持偏函数
偏函数的简写形式
val list = List(2, 4, 6, 8, "cat")
//定义一个偏函数
def myPartialFunction: PartialFunction[Any, Int] = {
case x: Int => x * x
}
list.collect(myPartialFunction).foreach(println)
****// 简写方式
list.collect({
case x:Int=>x*x
}).foreach(println)
匹配模式
模式匹配,其实类似于Java中的swich case语法,即对一个值进行条件判断,然后针对不同的条件,进行不同的处理。
但是Scala的模式匹配的功能比Java的swich case语法的功能要强大地多,Java的swich case语法只能对值进行匹配。但是Scala的模式匹配除了可以对值进行匹配之外,还可以对类型进行匹配、对Array和List的元素情况进行匹配、对case class进行匹配、甚至对有值或没值(Option)进行匹配。
而且对于Spark来说,Scala的模式匹配功能也是极其重要的,在spark源码中大量地使用了模式匹配功能。
基本语法
_ match {
case _ 2 => TODO
case _1 => TODO
case _ =>
}
/**
* 牛逼的匹配模式
*
* @param arg
*/
def test1(arg: Any) = arg match {
case x: Int => println("输入的参数是一个Int类型")
case x: (String, Int) => println(s"输入的是一个元组:$x")
case arr: Array[Int] => println(s"这是一个数组: " + arr(0))
case _ => println("我不知道你是个啥")
}
字符串
匹配模式可以对字符串进行内容匹配!!
def test3(arr:Array[String]): Unit ={
// 生成一个随机的整数数据 随机取出数组中的一个元素
val index: Int = Random.nextInt(arr.length)
arr(index) match {
case "DOIT_TAOGE" => println("涛哥")
case "DOIT_XINGGE" => println("星哥")
case "DOIT_XIAOHANG" => println("小行")
case "DOIT_NANA" => println("娜姐")
case _ => println("这个是小胡")
}
}
def main(args: Array[String]): Unit = {
val arr = Array[String]("DOIT_TAOGE","DOIT_XINGGE","DOIT_XIAOHANG","DOIT_NANA","DOIT_CLS")
test3(arr)
}
数据类型
def test4(arr:Array[Any]){
// 生成一个随机的整数数据 随机取出数组中的一个元素
val index: Int = Random.nextInt(arr.length)
arr(index) match {
case m: Map[_, _] => "Map:" + m.size
case t: (_, _) => "Tuple2: " + t._1 + "," + t._2
case x:Int => //TODO
case x:String=> print("哈哈哈")//TODO
case x:Double => //TODO
case x:Boolean=> //TODO
case Person=> //TODO
case _ => //TODO
}
}
元组
/**
* 匹配元组
* 同时可以匹配指定元组元素的数据类型
* @param arg
*/
def tupleMatch(arg:Any): Unit ={
arg match {
case (x:Int,y:Int)=> print(s"IntType:$x , $y")
case(x:String ,y:String)=>print(s"Stringtype: $x , $y")
case (x,y,z) =>print(s"$x , $y , $z")
case _ =>print(s"wakaka~~")
}
}
List和Array
数组
val arr: Array[Any] = Array[Any]("abc",12,3,4,5,6)
arr match {
/case Array(x,_,_,_,_,_) => print(s"$x")
case Array("abc",_*) =>print("这个数组是以字符串abc开头 : "+arr.length)
case _ => println("hah")
}
List
val lst = List(3, 5, 6, 7)
lst match {
case 1 :: x :: y => println(s"x=${x},y=${y}")
case List(x, y, z, d) => println("match ")
case x :: y :: c :: d :: z => println(s"x=${x},z=${z}")
case _ => println("no match ")
}
样例类和样例对象
abstract class Animal
case class Cat(name: String) extends Animal
case class Dog(name: String) extends Animal
case class Monkey(name: String) extends Animal
case object Hours(name: String) extends Animal
/**
* 匹配样例类
* @param arg
* @return
*/
def test2(arg: Any) = arg match {
case Cat(_) => ("这是一只猫" + arg)
case Dog(_) => ("这是一只狗" + arg)
case Monkey(_) => ("这是一只猴子" + arg)
case _ => ("这是个啥玩意??")
}
//测试
println(test2(Cat("喵...")))
println(test2(Dog("汪...")))
println(test2(Monkey("咯咯...")))
println(test2(Hours("呃呃")))
Option
val map = Map("yangzi"->27,"reba"->30 ,"yangmi"->41)
val res: Int = map.get("fengjie") match {
case Some(v) => v
case None => -1
}
println(res)