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中参数传递的方式有两种,一种是传值调用,一种是传名调用
①传值调用(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 } }