Java在1.8版本的时候,引入了Lambda表达式,Lambda表达式指的是应用在单一抽象方法接口环境下的一种简化定义形式,可以用于解决匿名内部类的定义复杂问题。
匿名内部类
匿名内部类的产生原因
public class Demo {
public static void main(String[] args) {
// 创建对象
MyRunnable runnable = new MyRunnableImpl();
// 对象调用方法
runnable.run();
}
}
// 定义一个接口
interface MyRunnable {
public void run();
}
// 接口的实现类
class MyRunnableImpl implements MyRunnable {
@Override
public void run() {
System.out.println("Run...");
}
}
结果
Run...
一个简单的接口,在我们再主方法中使用之前,需要先实现它的方法,这样很不方便,所以我们出现了匿名内部类的方式来解决这个问题。
public class Demo {
/**
* 匿名内部类
*/
public static void main(String[] args) {
new MyRunnable() {
@Override
public void run() {
System.out.println("Run...");
}
}.run();
}
}
// 定义接口
interface MyRunnable {
public void run();
}
结果
Run...
我们直接使用了匿名内部类,不需要去再去创建一个接口实现类,然后再拿来实例化对象,结果一样,只是把重写的方法拿到我们需要用的地方去操作。缺点就是看起来没有不使用匿名内部类看起来更加直观。
Lambda方式
java为了简化代码量,让编程更加的便捷,引入了Lambda表达式。
public class Demo {
public static void main(String[] args) {
MyRunnable myRunnable = () -> {
System.out.println("Run...");
};
}
}
// 定义接口
interface MyRunnable {
public void run();
}
两者比较,Lambda表达式,更加的方便快捷,不用重写方法。lambda表达式本质是接口的子实现,lambda表达式简化了匿名内部类的写法,lambda表达式另一个叫法是函数式编程。接口增加@FunctionalInterface注解,视为函数式接口,加上这个注解的接口,如果不满足函数式接口的规范(只有一个抽象方法,但是可以有非抽象方法的接口),编译器就会报错。
lambda表达式重要特征
定义两个接口,一个一个参数,一个两个参数
// 定义接口
@FunctionalInterface
interface MathOperation {
int operation(int a, int b);
}
// 定义接口
@FunctionalInterface
interface Number {
int getNumber(int c);
}
(1)可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
// 使用类型声明
MathOperation addition = (int a, int b) -> a + b;
// 不使用类型声明
MathOperation addition = (a, b) -> a + b;
(2)可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
// 一个参数可以省略圆括号
Number number = b -> 2 * b;
// 多个参数不能省略圆括号且需要用逗号隔开
MathOperation addition = (a, b) -> a + b;
(3)可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
// 主体包含了一个语句,就不需要使用大括号
MathOperation add = (int a, int b) -> a+b;
// 主体包含了多个语句,就必须使用大括号,使用大括号就需要返回一个数值。
MathOperation add = (int a, int b) -> {a++;return a+b;};
(4)可选的返回关键字(return):如果主体只有一个表达式返回值则编译器会自动返回值,使用大括号需要指定表达式返回了一个数值。
// 主体只有一个表达式返回值则编译器会自动返回值,下面等同于{return a + b;}
MathOperation add1 = (int a, int b) -> a + b;
// 表达式使用大括号需要指定表达式返回了一个数值。
MathOperation add = (int a, int b) -> {return a + b;};
lambda表达式变量的作用域问题
(1)lambda表达式引用外层成员变量,如果外层成员变量为final,则在lambda内部不能修改成员变量的值,如果外层成员变量不为final,则在lambda内部能修改成员变量的值。
// 外层成员变量为final
static final int number = 1;
public static void main(String[] args) {
String str = "str";
GreetingService service = message -> {
number++;//不能修改成员变量的值,编译报错
System.out.println("hello " + message + str);
};
service.sayMessage("yang");
}
--------------------------------------------------------------------------------------------
//外层成员变量不为final
static int number = 1;
public static void main(String[] args) {
String str = "str";
GreetingService service = message -> {
number++;//可以修改成员变量的值,编译通过
System.out.println("hello " + message + str);
};
service.sayMessage("yang");
}
(2)lambda 表达式的局部变量可以不用声明为 final,但是必须不可被后面的代码修改(即隐性的具有 final 的语义)
String str = "str";
GreetingService service = message -> System.out.println("hello " + message + str);
service.sayMessage("yang");
str = "11"; // 编译报错
(3)lambda表达式不允许声明一个与局部变量同名的参数或局部变量。
// 局部变量名称为str,lambda表达式参数为message可行
String str = "str";
GreetingService service = message -> System.out.println("hello" + message);
--------------------------------------------------------------------------------------------
// 局部变量名称为str,lambda表达式参数为str不行,编译报错
String str = "str";
GreetingService service = str-> System.out.println("hello" + str);
方法的引用方式用类名::方法名,其本质还是lambda表达式。
// Car类
class Car {
// 静态方法,创建Car对象
public static Car create(final Supplier<Car> supplier) {
return supplier.get();
}
// 静态方法,碰撞
public static void collide(final Car car) {
System.out.println("Collided " + car.toString());
}
// 普通方法,跟随
public void follow(final Car another) {
System.out.println("Following the " + another.toString());
}
// 普通方法,维修
public void repair() {
System.out.println("Repaired " + this.toString());
}
}
@FunctionalInterface
interface Supplier<T> {
T get();
}
(1)引用构造方法:类名称::new
// 匿名内部类写法
Car dataInfo = Car.create(new Supplier<Car>() {
@Override
public Car get() {
return new Car();
}
});
//java8的lambda写法
Car car2 = Car.create(()->new Car());
System.out.println(car2);
//java的方法的引用
Car car3 = Car.create(Car::new);
System.out.println(car3);
(2)静态方法的引用:类名称::静态方法的名称
// 引用构造器
Car dataInfo2 = Car.create(Car::new);
List<Car> list = Arrays.asList(dataInfo2);
list.forEach(Car::collide);
(3)特定任意的对象引用方法:类名称::非静态方法的名称
// 引用构造器
Car dataInfo2 = Car.create(Car::new);
List<Car> list = Arrays.asList(dataInfo2);
list.forEach(Car::repair);
(4)特定对象的方法引用方法:instance::非静态的方法的名称
// 引用构造器
Car dataInfo2 = Car.create(Car::new);
List<Car> list = Arrays.asList(dataInfo2);
list.forEach(dataInfo2 ::follow);
public class Demo {
public static void main(String[] args) {
Vehicle v = new Car();
v.y();
Vehicle.c();
}
}
interface Vehicle {
/**
* 在接口中可以放置有方法体的方法,但方法必须用default来修饰 在接口添加默认方法,是用来给所有的子类提供一个功能
*/
default void y() {
System.out.println("y");
}
/**
* 在接口中还可以放置静态方法,静态方法需要有方法体
*/
static void c() {
System.out.println("c");
}
}
class Car implements Vehicle {
}
结果
y
c
https://blog.csdn.net/yy139926/article/details/128704893