Lambda是java8的重要更新,Lambda表达式支持将代码块作为方法参数,Lambda表达式允许使用更简洁的代码来创建只有一个抽象方法的接口(函数式接口)的实例。
一、组成部分
1.形参列表。允许省略参数类型,如果只有一个形参,可以省略()
2.箭头(->)。英文的划线与大于符号
3.代码块。如果只有一句代码,可以省略大括号{},如果需要返回值且只有一句代码,可以省略return和{}
例子:
package lambda;
interface Move{
void run();
}
interface Pay{
int money(int i);
}
interface Flyable{
void fly(String weather);
}
public class LambdaTest2 {
public void run(Move move){
move.run();
}
public int pay(Pay p){
return p.money(15);
}
public void fly(Flyable f){
f.fly("下大雨");
}
public static void main(String[] args) {
LambdaTest2 test = new LambdaTest2();
test.run(()->System.out.println("正在跑步...")); //无参数使用(),若只有一个形参,可以省略()
//代码块只有一句,可以省略{}
int money = test.pay((i)->i*2); //有返回值的,如果只有一句代码,则自动返回这句的结果
System.out.println("买两件需要支付:"+money);
test.fly((weather)->
{
System.out.println("今天的天气是:"+weather);
System.out.println("飞机飞行正常");
});
}
}
二、Lambda限制条件
1.函数式接口:
只有一个抽象方法,可以有多个默认方法,类方法,常量。可以使用注解@FunctionalInterface告诉编译器严格检查
1.Lambda的目标类型必须是函数式接口类型
2.Lambda表达式只能为函数式接口创建接口
2.目标类型:
a.将Lambda表达式赋值给一个函数式接口
b.将Lambda表达式作为一个函数式接口的参数传递给方法
c.将Lambda强制转化为指定函数式接口
实例:
package lambda;
public class LambdaTest3 {
public static void main(String[] args) {
Runnable runnable = ()->{
for(int i=0;i<100;i++){
System.out.println(i);
}
};
//编译出错,目标类型必须是明确的函数式接口
/*Object runnable2 = ()->{
for(int i=0;i<100;i++){
System.out.println(i);
}
};*/
//编译通过
Object runnable2 = (Runnable)()->{
for(int i=0;i<100;i++){
System.out.println(i);
}
};
}
}
三.方法引用与构造器引用
package lambda;
import javax.swing.JFrame;
@FunctionalInterface
interface Converter{
Integer convert(String num);
}
interface Test{
//定义一个常量 自动加上 public static final
int x = 5;
String test(String a,int i,int j);
//接口中的默认方法
default int add(int i,int j){
return i+j;
}
}
interface MyTest{
JFrame show(String title);
}
/**
* @author hk
* 方法引用、构造器引用
*/
public class LambdaTest4 {
public static void main(String[] args) {
/*******引用类方法 *****/
Converter converter = (String num)->Integer.parseInt(num);
//Converter converter = (num)->Integer.parseInt(num); //形参列表允许省略形参类型
int num = converter.convert("123");
//方法引用代替lambda表达式
//函数式接口中的方法的全部参数传递给该类方法作为参数
Converter converter2 = Integer::parseInt;
int num2 = converter2.convert("123");
/*******引用特定对象的实例方法 *****/
Converter converter3 = (sub)->"hekui1997.com".indexOf(sub);
Integer index = converter3.convert("ui");
System.out.println(index); //输出3
//方法引用代替lambda表达式
Converter converter4 = "hekui1997.com"::indexOf;
int i = converter4.convert("ui"); //参数"ui"将会传递给indexOf方法
/*******引用某类对象的实例方法 *****/
Test t = (a,b,c)->a.substring(b, c);
String str = t.test("I am so happy!", 2, 5);
//函数式接口的方法的第一个参数作为调用者,其余参数全部传递给该方法
Test t2 = String::substring;
String str2 = t2.test("I am so happy!", 2, 5);
System.out.println(str2);
System.out.println(str);
//尝试在lambda调用接口中的默认方法 编译失败,可以使用接口中的常量
//Test t3 = (a,b,c)->{int j = Test.x;int i = add(1,2);return a.substring(b, c);};
//但在匿名内部类中可以使用接口中的默认方法
/*Test t3 = new Test(){
@Override
public String test(String a, int i, int j) {
add(1, 2);
return null;
}
};*/
/*******引用构造器******/
MyTest mt = (title)->new JFrame(title);
JFrame frame = mt.show("you win!");
System.out.println(frame);
//函数式接口的方法的全部参数传递给该方法作为参数
MyTest mt2 = JFrame::new;
JFrame frame2 = mt2.show("you lost!");
System.out.println(frame2);
}
}
四.Lambda表达式与匿名内部类的联系与区别
1.匿名内部类可以为任何接口创建实例,不管接口中有多少个抽象方法,但是Lambda只能为函数式接口创建实例。
2.匿名内部类可以可以为抽象类或普通实例创建实例,Lambda只能为函数式接口创建实例。
2.匿名内部类实现抽象类的方法的方法体中可以调用接口中的默认方法,但是Lambda表达式不能