一、Java Lambda表达式
Java lambda表达式是Java 8新特性,它是步入Java函数式编程的第一步,它可以像一个对象一样传递,并按要求执行。
函数式接口
- 一种只含有一个抽象方法声明的接口
- 可以使用匿名内部类来实例化函数式接口的对象
- 通过Lambda表达式可以进一步简化代码
Lambda表达式语法
-
(parameters) -> expression
-
(parameters) ->{ statements;...... }
首先新建一个接口OperationInterface
public interface OperationInterface {
Integer option(Integer a,Integer b);
}
创建测试类TestOperation
// 定义加减乘的Lambda表达式
OperationInterface add = (Integer a,Integer b) -> a+b;
OperationInterface sub = (Integer a,Integer b) -> a-b;
OperationInterface multi = (Integer a,Integer b) -> a*b;
// 调用
System.out.println(add.option(10,20)); // 30
System.out.println(sub.option(10,20)); // -10
System.out.println(multi.option(10,20)); // 200
二、Scala函数
函数定义
def 函数名([参数列表]):[返回值]={ 函数体 return [表达式] }
函数调用
函数名(参数列表)
参数传递
在scala中参数传递的方式有两种,一种是传值调用,一种是传名调用
- ①传值调用(call-by-value):传值调用时,参数只在调用时计算一次,后续重复使用计算的结果
- ②传名调用(call-by-name):传名调用时,参数在调用时不会计算,只有真正用到参数时才计算
// 定义两个函数
object Demo {
// 传名调用,参数名称和参数类型中间有一个=>符号,即b: => Int
def addByName(a: Int, b: => Int) = a + b
// 传值调用
def addByValue(a: Int, b: Int) = a + b
// 当a=1,b=2+2时,分别执行上述两个方法
addByName(1,2+2)
/*
addByName(1,2+2)
=> 1+(2+2)
=> 1+4
=> 5
*/
addByValue(1,2+2)
/*
addByValue(1,2+2)
=> addByValue(1,4)
=> 1+4
=> 5
*/
}
两种参数传递方式的理解:
// 以猴子吃桃子为例,一共10个桃子,每天吃一个,假设猴子会数桃子数量
object EatPeach{
// 桃子数量
var peach_num = 10
// 吃桃子,桃子数量-1
def eat={
peach_num = peach_num - 1
}
// 每次吃完,数一次桃子
def count={
eat
peach_num
}
// 通过两种方式计算桃子数量
// 传名调用
def printByName(x: => Int)={
for(i <- 1 to 5)
println("还剩"+x+"个桃子")
}
// 传值调用
def printByValue(x:Int)={
for(i <- 1 to 5)
println("还剩"+x+"个桃子")
}
// 测试
def main(args: Array[String]): Unit = {
println("------传名调用------")
printByName(count)
println("------传值调用------")
printByValue(count)
}
}
运行结果如下:
通过上述例子可看出:
传值调用在进入函数体之前就对参数表达式进行了计算,这避免了函数内部多次使用参数时重复计算其值,在一定程度上提高了效率。
传名调用的一个优势在于,如果参数在函数体内部没有被使用到,那么它就不用计算参数表达式的值了。在这种情况下,传名调用的效率会高一点。
命名参数
通常情况下,传入参数与函数定义的参数列表一一对应,命名参数允许使用任意顺序传入参数。如下例子:
// 定义函数
def showMessage(name:String,age:Int)={
println("Hello:"+name+",age:"+age)
}
// 传递的实参需要依照形参顺序
showMessage("KB09",3)
// 命名参数,通过指定参数名称对参数进行赋值,顺序可变
showMessage(age=18,name = "kb09")
参数缺省值
给定参数一个默认值,当实参为空时,该参数的值就为默认值
def showMessage(name:String="张三",age:Int=24)={
println("Hello:"+name+",age:"+age)
}
showMessage() // 输出Hello:张三,age:24
匿名函数
顾名思义,即指没有名称的函数
- 语法:
(参数列表)=>{函数体}
// 正常函数,有个名字,本例为sum
def sum(a:Int,b:Int)=a+b
// 匿名函数,没有名字
(a:Int,b:Int)=>a+b
// 使用匿名函数一定用一个变量接收
val sum1 = (a:Int,b:Int)=>a+b
// 使用
sum1(1,2) // 3
高阶函数
高阶函数是指将其他函数作为参数或者使用函数作为输出结果
- 将其他函数作为参数
// 定义一个函数,参数为(Int,Int)=>Int类型的函数
def fun(f:(Int,Int)=>Int):String={
val resultValue=f(1000,2000)
"两数之和为:"+resultValue
}
// 实参为一个匿名函数,该匿名函数作用是求两数之和
val result = fun((a:Int,b:Int)=>a+b)
println(result) // 3000
- 函数返回值为函数
// 传入一个参数,若该数大于2则返回求两数之和的函数,否则返回求两数之差的函数
def fun2(x:Int):(Int,Int)=>Int={
if(x>2){
// 求两数之和的函数
def add(a:Int,b:Int):Int=a+b
// 若x>2将add作为返回值
add
}else{
// 求两数之差的函数
// 匿名函数形式
(a:Int,b:Int)=>a-b
}
}
// fun2(1)(1,5)形式为柯里化,下面会讲到
println(fun2(1)(1,5)) // -4
- 参数为函数,返回值也为函数
// 以下代码可能并无实际意义,主要是为了演示
def fun3(f:(String)=>Int,str:String):(Int,Int)=>Int={
val num = f(str)
if(num%3==0){
(a:Int,b:Int)=>a+b
}else{
(a:Int,b:Int)=>a-b
}
}
println(fun3((s: String) => {
if (s.equals("上海"))
1
else
2
}, "张三")(1000, 3000))
柯里化
函数可以定义多个参数列表,当使用较少的参数列表调用多参数列表的函数时,会产生一个新的函数,该函数接收剩余的参数列表作为其参数,这被称为柯里化
// fun4、fun5作对比
def fun4(a:Int,b:Int,c:Int,d:Int):Int={
a+b+c+d
}
println(fun4(1,2,3,4))
def fun5(a:Int)(b:Int)(c:Int)(d:Int):Int={
a+b+c+d
}
println(1)(2)(3)(4)
隐式参数
隐式参数用implicit修饰,通常与柯里化函数结合使用,如下例:
// 将a作为Int类型隐式值自动传递
implicit val a:Int = 10
// 定义一个函数func5,c为隐式参数,传值时会自动找同类型的隐式值
def fun5(a:Int,b:Int)(implicit c:Int)={
a+b+c
}
// c为隐式参数,已经定义了a为隐式值,故不需要传参
println("fun5的结果1:"+fun8(10,11)) // 31
// 可通过对隐式参数传参覆盖隐式值
println("fun5的结果2:"+fun8(10,11)(5)) // 26
// fun6与fun5的区别在于给定了隐式参数一个缺省值
def fun5(a:Int,b:Int)(implicit c:Int=5)={
a+b+c
}
// 给隐式参数c传递空值,用于比较隐式值与缺省值的优先级
println("fun6的结果:"+fun8(10,11)()) // 31
注意:上述比较可以得出结论:对隐式参数赋值三种方式的优先级为:直接传参 > 隐式值 > 缺省值 ;同一类型的隐式值只能有一个,否则会报错
隐式函数
隐式函数也称隐式转换,使用implicit修饰的函数
应用场景:
- 类型转换
object ImplicitFunc{
def main(args: Array[String]): Unit = {
// 定义了一个隐式函数,该函数的作用是将double类型转成int类型
implicit def doubleToInt(value:Double):Int=value.toInt
// 因为有隐式函数,故可以这么操作,隐式函数会自动调用
val num:Int = 3.5
println(num) // 3
}
}
- 类型增强
object ImplicitFunc{
def main(args: Array[String]): Unit = {
implicit def bool2Int(x:Boolean)=if(x) 1 else 0
println(1+true) // 2
}
}