简介
Lambda表达式和方法引用是 Java 8 提供的新特性,开发人员可以通过编写函数式接口,使用Lambda表达式和方法引用实现函数式接口。使得接口像函数一样去使用,从而实现函数式编程
参考资料
概念
函数式接口
接口中只有单一且需要实现的方法,就是函数式接口。使用@FunctionalInterface,可以强制约束为函数式接口,在编译时,接口中的未实现方法大于一个,就会编译错误。
/**
* 单一未实现的方法接口(函数式接口)
* @FunctionalInterface注解约束接口只能有一个未实现的方法
*/
@FunctionalInterface
interface TestFunctionalInterface{
int add(int b);
}
Lambda表达式
Lambda表达式(匿名函数),可以在任意地方创建函数式接口的实现
Lambda表达式语法
// b 是接口中add方法的参数,与接口方法参数数量相同,类型可以不指定
// -> 指向实现的方法
// {} 接口的实现方法
TestFunctionalInterface testFunc = (b)->{
return b+1;
};
//简约写法,
//只有一个参数时,可以不用括号
TestFunctionalInterface testFunc = b -> {
return b+1;
};
//只有一个行代码时,可以不用大括号和return关键词
TestFunctionalInterface testFunc = b -> b+1;
示例代码:
package com.studyjava.Lambda;
public class Java8Lambda表达式 {
/**
* 接口中只有单一的方法,使用@FunctionInterface注解后,就成了函数式接口
*/
interface TestFunctionalInterface{
int add(int b);
}
public static void main(String[] args){
//单独声明变量
System.out.println("单独声明变量使用");
TestFunctionalInterface testFunc = (b)->{
return b+1;
};
int result = testFunc.add(10);
System.out.println("result=>" + result + "\n");
//使用在方法参数中
System.out.println("在方法参数中使用");
result = addOne((b)->{ return b+1;});
System.out.println("result=>" + result + "\n");
//声明变量传递给方法参数使用
System.out.println("声明变量传递给方法参数使用");
TestFunctionalInterface testFunc2 = (b)->{
return b+1;
};
result = addOne(testFunc2);
System.out.println("result=>" + result + "\n");
}
public static int addOne(TestFunctionalInterface testFunc){
return testFunc.add(10)+1;
}
}
方法引用
方法引用:可以将方法或静态方法做为函数式接口的实现。
方法引用语法:
//函数式接口
interface TestInterface{
int add(int b);
}
class Java8MethodRef{
//对象方法
public int add(int b){
return b+1;
}
//类方法(静态方法)
public static int staticAdd(int b){
return b-1;
}
public static void main(String args[]){
//对象方法用作参数[变量名]::方法名
Java8MethodRef java8MethodRef = new Java8MethodRef();
TestInterface testInterface = java8MethodRef::add;
//静态方法用作参数[类名]::方法名
TestInterface testInterfaceStatic = Java8MethodRef::staticAdd;
}
}
方法引用使用需注意:
- 方法引用只能作用在函数式接口中
- 方法的方法名可以与接口的方法不一样
- 方法的参数数量、参数类型以及返回值类型要和接口的方法一样
示例代码:
package com.studyjava.Lambda;
public class Java8MethodRef {
/**
* 单一未实现的方法接口(函数式接口)
* @FunctionalInterface注释约束接口只能有一个未实现的方法
*/
@FunctionalInterface
interface TestInterface{
int add(int b);
}
/**
* 对象方法
*/
public int sub(int b){
return b+1;
}
/**
* 静态方法
*/
public static int staticSub(int b){
return b-1;
}
public static void main(String[] args) {
//使用Java8MethodRef对象方法引用
Java8MethodRef java8MethodRef = new Java8MethodRef();
useTestInterface(java8MethodRef::sub);
//使用声明接口变量再调用
TestInterface testInterface = java8MethodRef::sub;
useTestInterface(testInterface);
//使用静态方法引用
TestInterface testInterface2 = Java8MethodRef::staticSub;
useTestInterface(testInterface);
}
/**
* 使用接口方法引用
* @param testInterface
*/
public static void useTestInterface(TestInterface testInterface){
int add = testInterface.add(1);
System.out.println("useTestInterface==>"+add);
}
}
总结
-
Lambda表达式与方法引用只能用在函数式接口上
-
函数式接口是为了让方法与接口本身绑定,实现方法就是实现整个接口。让接口像函数一样
- 单一方法的接口是函数式接口。使用@FunctionalInterface注解强制约束接口只有一个方法
- 函数式编程中,函数作为第一等公民,可以像变量一样创建、赋值、传参
-
Lambda表达式与方法引用是为了从编程方式上,实现函数式编程
-
Lambda表达式是为了方便创建函数式接口的实现
-
方法引用是为了可以使用与函数式接口方法参数数量、参数类型、返回值类型相同的方法,作为函数式接口的实现。实现函数式接口的赋值
-
实现原理
Lambda表达式
- 在类编译时,会生成一个私有静态方法+一个内部类。
- 在内部类中实现了函数式接口,在实现接口的方法中,会调用编译器生成的静态方法。
- 在使用Lambda表达式的地方,通过传递内部类实例,来调用函数式接口方法。
详细见参考网址:Java Lambda表达式表达式 实现原理分析
方法引用(推测)
方法引用是使用其它类中的方法。那么只需要给接口实现一个匿名的实现类,并在类的方法里调用被引用的方法即可。代码如下 :
TestInterface testInterface = java8MethodRef::sub;
//运行时的代码
TestInterface testInterface = new TestInterface(){
public int add(int b){
return java8MethodRef.sub(b);
}
}