目录
一:scala的函数
0.函数之于 java/scala地位
特点:
函数与类、对象一样,都是一等公民
现在只是一门语言,应用于数据分析领域(更加卓著)
Java的生态:
重要的框架和系统太多:
Spring:大型项目
Lucene:给项目加上索引
Activiti:工作流的系统
Hadoop:大数据
1.scala中的函数
定义:与java中的函数必须依托于某个类而言。在scala中它可以独立定义,独立存在。
将函数赋值给变量的固定写法:
必须在 ”函数名称“ 后面加上 “空格”和“下划线” ,不带 “()”
例子:
def sayHello(name: String) { println("Hello, " + name) }
val sayHelloFunc = sayHello _
怎么通过被赋予值的变量去使用函数?作用?
直接传递函数的名称是否可行??
例子:
sayHelloFunc("leo")
能否使用 var 变量类型进行接收
例子:
def sayHello(name: String) { println("Hello, " + name) }
var sayHelloFunc = sayHello _
//可行
2.匿名函数
(1)语法规则:(函数名: 参数类型) => {方法体}
(2)作用:1>将函数赋予值给某个变量
2>直接将匿名函数传入到其它函数
例子:
val sayHelloFunc = (name: String) => println("Hello, " + name)
sayHelloFunc("Tom")
//输出:Hello,Tom
(3)特性:函数名称直接当成变量去使用
例子2:
def sayHelloFunc(name:String)=println("Hello, "+name)
def greeting(func:(String)=>Unit,name:String)=func(name)
val sayHelloFunc2 = sayHelloFunc _
scala> greeting(sayHelloFunc,"leo")
scala> greeting(sayHelloFunc2,"leo")
//Hello, leo
3.高阶函数
(1)将函数当成参数进行传递
1>以函数作为传入参数的函数的书写规范:
func:(String)=>Unit
函数变量名称 + “:" + "(传参类型)" + “返回值类型”
例子:
val sayHelloFunc = (name: String) => println("Hello, " + name)
def greeting(func:(String) => Unit,name:String){ func(name)}
greeting(sayHelloFunc, "leo")
java事例:
public Class SayHello{
public abstract sayHello();
}
public void greeting(String name,new SayHello(){
public void sayHello(String name){System.out.println("Hello, "+name)}
})
{
sayHello.sayHello(name)
}
好处:对比Java,它的代码更加的简洁
2>
例子2:
Array的高阶函数
Array(1, 2, 3, 4, 5).map((num: Int) => num * num)
(2)将函数作为返回值
1.规则:只能直接定义一个匿名函数
2.构造方式:
def 函数名称(传参)=(传入参数)=>{方法体}
注意:必须用 “=” 等号连接
例子:
def getGreetingFunc(msg:String)=(name:String)=>{println(msg+","+name)}
创建结果:getGreetingFunc: (msg: String)String => Unit
val greetingFunc = getGreetingFunc("hello")
//greetingFunc: String => Unit = <function1>
greetingFunc("leo")
// hello,leo
(3)是否有其它方式将函数变为返回值
(除去普通函数转变为变量)
例子:
def func1(name:String)=println("Hello, "+name)
def func2(name:String)=func1(name)
def func3()=println("Hello!")
val func4 = func3() ———— 本质只是返回Unit而已,而不是将函数本身返回了
so:只能用返回匿名函数的方式
(4)匿名函数作为返回值的作用
例子:
def getGreetingFunc(msg: String) = (name: String) => println(msg + ", " + name)
val greetingFunc = getGreetingFunc("hello")
greetingFunc("leo")
// hello,leo
val greetingFunc = getGreetingFunc("hi")
greetingFunc("leo")
// hi,leo
def f(x:Int,y:Int)=x+y
def g(x:Int)=f(x,1) ————》 函数的返回
作用:
更加灵活的定义函数的方式(类似函数的多态)
4.匿名函数当成参数传递
规则:
(参数名称:参数类型) => {函数体} ————》 在就是各种省略
(参数名称:参数类型) => 函数体
(参数名称) => 函数体
(参数名称) => 函数体
特点:
(1)高阶函数可以自动推断出参数类型,而不需要写明类型
为什么能够自动推断?(定义迭代函数时,必须主动声明类型)
1>本身在创建非迭代函数时,会依据最后一行的代码,scala可以自己分析返回类型
2>因为匿名函数肯定是非迭代函数,所以亦可分析
3>亦或者把迭代函数当成参数传递时,它本身肯定定义了返回值类型,所以亦可分析
(2)只有一个参数的函数,还可以省去其小括号
def greeting(func: (String) => Unit, name: String) { func(name) }
greeting((name: String) => println("Hello, " + name), "leo")
greeting((name) => println("Hello, " + name), "leo")
greeting(name => println("Hello, " + name), "leo")
(3)如果仅有的一个参数在右侧的函数体内只使用一次,则还可以将接收参数省略,并且将参数用_来替代
def triple(func: (Int) => Int)=func(3)
func: (Int) => Int : 定义了我要传递 传入参数入Int类型,返回值为Int类型的 函数
func(3) 是 triple函数的返回值
变形;
=》triple(num=>num)
=》3*triple(num=>num)
=》triple(3 * _)
变形的前提:必须有别的算子的加入,不然没有意义
例子:直接写 triple( _ )
scala> triple(_)
res5: (Int => Int) => Int = <function1>
深入理解: 仅有一个参数,并且在右侧的函数体内只使用一次
作用:参与后面高阶函数的简写
5.常用的高阶函数
本质理解(它们都以函数为传入参数)
(1)// map: 对传入的每个元素都进行映射,返回一个处理后的元素
Array(1, 2, 3, 4, 5).map(3 * _)
汇总: 享受简写 (当成把参数挨个进行传递后的计算)
Array(1, 2, 3, 4, 5).map((num: Int) => num) ————》 单个毫无作用
res0: Array[Int] = Array(1, 2, 3, 4, 5)
Array(1, 2, 3, 4, 5).map(3*_)
不使用简写:
Array(1,2,3,4,5).map(new Array(){
def map(num:Int)=num*3
})
(2) "(1 to 9).map("*" * _).foreach(println _)"
*
**
***
****
*****
******
*******
********
(3) "(1 to 20).filter(_ % 2 == 0)"
对传入的每个元素都进行条件判断,如果对元素返回true,则保留该元素,否则过滤掉该元素
(4)"(1 to 9).reduceLeft( _ * _)"
进行reduce操作,即先对元素1和元素2进行处理,然后将结果与元素3处理,再将结果与元素4处理,
依次类推,即为reduce
// 下面这个操作就相当于1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9
//res10: Int = 362880
(5)sortWith: 对元素进行两两相比,进行排序
Array(3, 2, 5, 4, 10, 1).sortWith(_ < _)
6.闭包
含义:函数在变量不处于其有效作用域时,还能够对变量进行访问
例子:
def getGreetingFunc(msg: String) = (name: String) => println(msg + ", " + name)
val greetingFuncHello = getGreetingFunc("hello")
val greetingFuncHi = getGreetingFunc("hi")
//greetingFuncHello("Tom") -- hello,Tom
//greetingFuncHi("Tom") -- hi,Tom
逻辑分析:
1>msg只是存在于匿名函数中的一个局部变量,
2>在getGreetingFunc执行完之后,还可以继续存在被变量 greetingFuncHello/greetingFuncHi 当做返回值接受的新建函数之中
3>greetingFuncHello("Tom"),在超出了其作用域的情况下,被再次调用
4>其中msg变量在被调用时超出了其作用域,还可以使用
实现原理:
作为函数对象的实例变量来存储(而不是继续作为局部变量的含义)
7.SAM转换:待续
(1)什么是SAM:
不支持直接将函数传入一个方法作为参数,通常来说,唯一的办法就是定义一个实现了某个接口的类的实例对象,该对象只有一个方法;而这些接口都只有单个的抽象方法,也就是single abstract method,简称为SAM
在scala中的代码实例: (似乎在讲Java )
val button = new JButton("Click")
button.addActionListener(new ActionListener {
override def actionPerformed(event: ActionEvent) {
println("Click Me!!!")
}
})
(2)scala在将java的函数当做变量进行传递时使用隐式转换
隐式转换特性:SAM转换,即将SAM转换为Scala函数
例子:
implicit def getActionListener(actionProcessFunc: (ActionEvent) => Unit) = new ActionListener {
override def actionPerformed(event: ActionEvent) {
actionProcessFunc(event)
}
}
button.addActionListener((event: ActionEvent) => println("Click Me!!!"))
8.Currying 函数(函数柯里化)
含义:将原来接收两个参数的一个函数,转换为两个函数,
第一个函数接收原先的第一个参数,然后返回接收原先第二个参数的第二个函数
本质:匿名函数的简化语法糖,简化了函数的声明,调用,函数与函数的组合
表现形式:
def sum(a: Int, b: Int) = a + b //sum(1, 1)
def sum2(a: Int) = (b: Int) => a + b //sum2(1)(1)
//匿名函数的简写
def sum3(a: Int)(b: Int) = a + b
复杂调用:
val s1=sum2(1)
val s2 = s1(2)
简单调用:
sum3(1)(2)
作用:
与偏应用函数有关,更加方便了函数与函数之间的组合!!
详解;https://www.cnblogs.com/mataszhang/p/5683654.html
9.scala中带名函数return的使用
return使用的时机:给匿名函数外面的带名函数进行返回值传递
特点:匿名函数中,一定要声明返回的类型
带名函数:有名称的函数(与匿名函数对立)
def greeting(name: String) = {
def sayHello(name: String):String = {
return "Hello, " + name
}
sayHello(name)
}
10.Lambda表达式
含义:理解为简洁地表示可传递的匿名函数的一种方式:它没有名称,但它有参数列表、函数主体、返回类型,可能还有一个可以抛出的异常列表。
二:重点的创建规则汇总
1.匿名函数的创建
(函数名: 参数类型) => {方法体}
2.把函数当参数书进行传递
(1)以函数作为传入参数的函数的书写规范
函数变量名称 + “:" + "(传参类型)" + “返回值类型”
func:(String)=>Unit
例子:
val sayHelloFunc = (name: String) => println("Hello, " + name)
def greeting(func:(String) => Unit,name:String){ func(name)}
greeting(sayHelloFunc, "leo")
(2)将匿名函数直接当成参数传递时的规范
(参数名称:参数类型) => {函数体} ————》 在就是各种省略
(参数名称:参数类型) => 函数体
(参数名称) => 函数体
(参数名称) => 函数体
例子:
def greeting(func: (String) => Unit, name: String) { func(name) }
greeting((name: String) => println("Hello, " + name), "leo")
greeting((name) => println("Hello, " + name), "leo")
greeting(name => println("Hello, " + name), "leo")
3.把函数传递给变量
1》传递普通函数
必须在 ”函数名称“ 后面加上 “空格”和“下划线” ,不带 “()”
例子:
def sayHello(name: String) { println("Hello, " + name) }
val sayHelloFunc = sayHello _
2》传递匿名函数
def 函数名称(传参)=(传入参数)=>{方法体}
例子:def getGreetingFunc(msg:String)=(name:String)=>{println(msg+","+name)}