目录
-
Lambda表达式主要是替换了原有匿名内部类的写法,也就是简化了匿名内部类的写法
-
lambda语法结构:
lambda表达式的基本组成由 参数列表、->、方法体(单句时可不加大括号)三部分组成
(参数类型 参数名称) -> {业务代码块}
-
lambda表达式的重要特征:
-
可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
-
可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
-
可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
-
可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定表达式返回了一个数值。
-
1、不需要参数
public interface A {
int ma();
}
//创建实现A接口的匿名类对象
A a=new A() {
@Override
public int ma() {
return 5;
}
};
//方法体重只有一行代码可省略大括号,返回值不用return
A b=()->5;
//标准写法
A c=()->{return 5;};
A d=()->{//必须要返回值
//System.out.println("ni");
return 0;
};
2、接收一个参数
public interface B {
int ma(int x);
}
//创建实现B接口的匿名类对象
等价都输出20
B b=new B() {
@Override
public int ma(int x) {
return 2*x;
}
};
//标准写法
B b=x->2*x;
B b=(int x)->{return 2*x;};
3、接受两个参数
public interface C {
int ma(int x,int y);
}
C c=new C() {
@Override
public int ma(int x, int y) {
return x+y;
}
};
C c=(int x,int y)->{
return x+y;
};
C c=(x,y)->x+y;
System.out.println(c.ma(10,20));==30
4、接收String
public interface D {
void String(String str);
}
D d=new D() {
@Override
public void String(String str) {
System.out.println(str);
}
};
D d=(String str)->{
System.out.println(str);
};
D d=str-> System.out.println(str);
5、替代匿名内部类
public interface D {
void String(String str);
}
public class AnonymousInnerClass {
private String name = "bx";
private int age = 20;
// E e=new E() {
// @Override
// public void display() {
// System.out.println("name="+name+",age="+age);
// }
// };//等价
E e = () -> System.out.println("name=" + name + ",age=" + age);
public static void main(String[] args) {
AnonymousInnerClass innerClass = new AnonymousInnerClass();
innerClass.e.display();
}
}
6、隐形final
public class Test {
private static final int a = 8; //常量
private int c = 20;
public static void main(String[] args) {
int a = 9;//定义局部变量
TestService service1 = new TestService() {
@Override
public void test() {
System.out.println(a);
//a = a + 2; //把局部变量当隐形final,在匿名内部类方法中 不能修改局部变量值
//System.out.println(c); //不能调用非静态的成员变量
System.out.println("匿名内部类对象实现 test方法");
ma(); //匿名内部类方法体内可以调用接口default方法(默认方法)
System.out.println(TestService.mm);
//匿名内部类的方法体内部定义变量,是可修改的
int ff = 0;
ff = ff + 2;
}
};
service1.test();
int b = 12;
//标准写法
TestService service2 = () -> {
//System.out.println(c); //lambda不能调用非静态的成员变量
System.out.println(b); //b 局部变量 具有隐形final含义
//b = b + 2; //把局部变量当隐形final,在匿名内部类方法中 不能修改局部变量值
System.out.println("标准写法lambda实现的test方法");
//ma(); //lambda方法体内不能调用接口default方法(默认方法)
System.out.println(TestService.mm);
//lambda的方法体内部定义变量,是可修改的
int ff = 0;
ff = ff + 2;
};
service2.test();
}
}
public class TestService1 {
int a = 10;
public void ccc() {
int c = 10;
final int d = 20;
TestService service1 = new TestService() {
@Override
public void test() {
System.out.println(a);//匿名类对象方法是可以修改和使用成员变量
a = a + 2;
System.out.println(c); //能够使用局部变量(隐含的final)
//c = c + 2; //修改c变量值就报错,说明在匿名内部类中局部变量b是看做是隐含的final
System.out.println(d);//能够使用final的局部不比变量
//d=d+30; //不能修改final变量
System.out.println("匿名内部类对象实现 test方法");
ma(); //匿名内部类方法体内可以调用接口default方法(默认方法)
System.out.println(TestService.mm);
//匿名内部类的方法体内部定义变量,是可修改的
int ff = 0;
ff = ff + 2;
}
};
Person p = new Person();
}
public void aaa() {
int b = 12;
//标准写法
TestService service2 = () -> {
System.out.println(a); //lambda是可以修改和使用成员变量
a = a + 2;
System.out.println(b); //能使的局部变量(隐含的final)
//b = b + 2; //修改就报错,就说明在lambda表达式方法中局部变量b是看做是隐含的final
System.out.println("标准写法lambda实现的test方法");
//ma(); //lambda方法体内不能调用接口default方法(默认方法)
System.out.println(TestService.mm);
//lambda的方法体内部定义变量,是可修改的
int ff = 0;
ff = ff + 2;
};
}
}
对返回的实例类型的要求
可以将lambda表达式当作任意只包含一个抽象方法的接口类型,确保你的接口一定达到这个要求,你只需要给你的接口添加** @FunctionalInterface** 注解,编译器如果发现你标注了这个注解的接口有多于一个抽象方法的时候会报错的
//函数式注解 (**编译时检查**)
//在接口上加入@FunctionalInterface注解,接口定义的抽象方法只能有一个,有多个时就会编译报错
@FunctionalInterface
public interface Z {
int abc();
// int bcd();
}
是否为接口添加@FunctionalInterface注解并不影响lambda表达式的功能
@FunctionalInterface注解只是为了在代码开发阶段由编译器帮助开发人员判定接口是否符合函数式接口的定义(是否适用于lambda表达式)
可以直接访问标记了final的外层局部变量或者实例的成员变量以及静态变量和匿名内部类,不同的是,局部变量可以不用声明为final,代码同样能够正确执 行,但变量必须不可被表达式的代码修改(即隐性的具有final的语义)
有一个和接口的默认方法相关的要点:Lambda表达式是无法访问到默认方法的