赞
踩
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
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。