lambda 表示式
Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。
Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。
Lambda表达式就必须使用函数式接口,如果使用函数式接口,那么该接口之中就只能有一个抽象方法(必须要有这个函数) @FunctionalInterface //添加此注解后,接口中只能有一个抽象方法(允许有默认方法(用defaultx修饰 java8新特性)和静态方法)
@FunctionalInterface
interface Test{
int add (int a,int b);
default int adds(int a,int b){
return a+b;
}
}
总结 替换了函数式接口的匿名函数创建
lambda 表达式的语法格式如下:
(parameters) -> expression 或 (parameters) ->{ statements; }
包含三部分:
1、一个括号内用逗号分隔的形式参数,参数是函数式接口里面方法的参数
2、一个箭头符号:->
3、方法体,可以是表达式和代码块
以下是lambda表达式的重要特征:
- 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
- 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
- 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
- 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定表达式返回了一个数值。
Lambda 表达式的简单例子:
// 1. 不需要参数,返回值为 5 () -> 5 // 2. 接收一个参数(数字类型),返回其2倍的值 x -> 2 * x // 3. 接受2个参数(数字),并返回他们的差值 (x, y) -> x – y // 4. 接收2个int型整数,返回他们的和 (int x, int y) -> x + y // 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void) (String s) -> System.out.print(s)
// 大括号中的返回语句
(int a, int b) -> { return a * b; };
变量作用域
1:lambda 表达式只能引用标记了 final 的外层局部变量,这就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。
2:lambda 表达式的局部变量可以不用声明为 final,但是必须不可被后面的代码修改(即隐性的具有 final 的语义)
3:在 Lambda 表达式当中不允许声明一个与局部变量同名的参数或者局部变量。
1.1 函数式接口
要注意的是想使用Lambda表达式就必须使用函数式接口,如果使用函数式接口,那么该接口之中就只能有一个抽象方法
Java中的lambda无法单独出现,它需要一个函数式接口来盛放,lambda表达式方法体其实就是函数接口的实现.
举例:
package com.yztcedu.lambdademo_01;
@FunctionalInterface //添加此注解后,接口中只能有一个抽象方法。
public interface A {
void call();
}
1.4 默认方法---接口改进
简单说,就是接口可以有实现方法,而且不需要实现类去实现其方法。只需在方法名前面加个default关键字即可。
package com.yztcedu.lambdademo_01;
@FunctionalInterface
public interface A {
void call();
default void fun() {
System.out.println("我是接口的默认方法1中的代码");
}
default void fun2() {
System.out.println("我是接口的默认方法2中的代码");
}
}
为什么要有这个特性?首先,之前的接口是个双刃剑,好处是面向抽象而不是面向具体编程,缺陷是,当需要修改接口时候,需要修改全部实现该接口的类
1.3 方法引用
其实是lambda表达式的一种简化写法。所引用的方法其实是lambda表达式的方法体实现,语法也很简单,左边是容器(可以是类名,实例名),中间是"::",右边是相应的方法名。如下所示:
如果是静态方法,则是ClassName::methodName。如 Object ::equals
如果是实例方法,则是Instance::methodName。如Object obj=new Object();obj::equals;
构造函数.则是ClassName::new
Runnable runnable = Demo2::run;
public static void run(){
System.out.println("方法引用的代码...");
}
public class WphOrderInfo {
@FunctionalInterface
public interface Supplier<T> {
T get();
}
//Supplier是jdk1.8的接口,这里和lamda一起使用了
public static WphOrderInfo create(final Supplier<WphOrderInfo> supplier) {
return supplier.get();
}
public static void collide(final WphOrderInfo car) {
System.out.println("Collided " + car.toString());
}
public void follow(final WphOrderInfo another) {
System.out.println("Following the " + another.toString());
}
public void repair() {
System.out.println("Repaired " + this.toString());
}
public static void main(String[] args) {
//构造器引用:它的语法是Class::new,或者更一般的Class< T >::new实例如下:
WphOrderInfo cart = WphOrderInfo.create(new Supplier<WphOrderInfo>() {
@Override
public WphOrderInfo get() {
return null;
}
});
WphOrderInfo car = WphOrderInfo.create(WphOrderInfo::new);
car.setId("0");
WphOrderInfo car1 = WphOrderInfo.create(WphOrderInfo::new);
car1.setId("1");
WphOrderInfo car2 = WphOrderInfo.create(WphOrderInfo::new);
car2.setId("2");
WphOrderInfo car3 = new WphOrderInfo();
car3.setId("3");
List<WphOrderInfo> cars = Arrays.asList(car,car1,car2,car3);
System.out.println("===================构造器引用========================");
//静态方法引用:它的语法是Class::static_method,实例如下:
cars.forEach(WphOrderInfo::collide);
System.out.println("===================静态方法引用========================");
//特定类的任意对象的方法引用:它的语法是Class::method实例如下:
cars.forEach(WphOrderInfo::repair);
System.out.println("==============特定类的任意对象的方法引用================");
//特定对象的方法引用:它的语法是instance::method实例如下:
final WphOrderInfo police = WphOrderInfo.create(WphOrderInfo::new);
police.setId("----------10085-------------");
cars.forEach(police::follow);
System.out.println("===================特定对象的方法引用===================");
}
}