java8的重要更新,其作用是代替内部类的繁琐语法,创建一个只有一个抽象方法的接口(即函数式接口)的实例(也可以进行赋值)。
组成:
(int elements)->{System.out.println("Hello Lambda");return 1;}
(形参列表):允许省略形参类型,如果形参列表允许只有一个参数括号可省略(java 11之前形参必须声明类型,不过编译器是能够推断出来的)
->: 符号
{代码块}:如果只包含一条语句,允许省略花括号;只有一条return语句可以省略return关键字,当需要返回值时会自动将此语句的值返回。
这里的内容都是给方法的方法的形参和方法体
使用
函数式接口:只有一个抽象方法的接口,可以定义多个默认方法和类方法,但是只能有一个抽象方法。比如创建线程时使用的Runnable
,(注解@FuctionalInterface;
这种接口使用)
Lambda表达式创建其实例相对于匿名内部类较为便捷(Lambda也就只能创建函数式接口,而且他赋值的对象类型只能是一个函数式接口 如果Object obj = ()->{}
会报错不兼容类型)
Lambda表达式的常见使用方式(保证目标类型为函数式接口)
- 赋值给函数式接口
- 作为函数式接口类型的参数传给某个方法
- 对Lambda表达式强转
Object obj = (Runnable)()->{方法体;}
注意:
Lambda表达式的目标类型可以变化但是必须和函数式接口中的抽象方法保持相同的形参列表。就是说同一个Lambda表达式只要形参列表相同可以强转后赋给多种对象
如果 用var声明一个对象 ,要用Lambda给其赋值必须强转指出其目标类型
var obj = (Runnable)()->{}
当需要对Lambda表达式的形参进行注解时,不能省略Lambda表达式的形参类型-因为注解只能被放在形参类型之前。这时可以用var来声明形参类型
方法引用和构造器引用
方法引用:当lambda表达式只有一条语句时,而且此语句调用了其他类的类方法或者其他对象的实例方法时可以使用简化的写法
示例
(假设obj为一个函数式接口)
1.引用静态方法:当lambda表达式语句需要调用其他类的类方法时
Object obj = (form)->integer::valueOf(from)
简洁形式可写为Object obj = Integer::valueOf;
使用此方式创建对象之后,当调用到其中的抽象方法时,就会去找Integerl类的valueOf方法并将形参直接代入进行运算
2.引用实例方法:当lambda表达式语句需要调用其他对象的实例方法时可使用
Object obj = ()->"String".indexOf(s);
简洁形式可写为Object obj = "String"::indexOf;
使用此方式创建对象之后,当调用到其中的抽象方法时,就会去找String类对象的indexOf方法并将参数传递到方法中运算
3.传入参数为多个时,会将第一个作为indexOf方法的调用者,其他的作为方法的参数
Object obj = (a,b,c)->a.subString(b,c);
简洁形式可写为Object obj = "String"::indexOf;
4.lambda表达式只创建了一个对象时
Object obj = a -> new JFrame(a);
简洁形式Object obj = JFrame::new;
创建对象之后,当调用到其中的抽象方法时,就会去找JFrame的构造函数,将其参数传递到构造函数里运行
匿名内部类和Lambda表达式的联系
1.都可以访问局部和外部类的成员变量(对于局部变量 未用final指定就会限制不可改变 effectively final)
2.两者创建的对象都可以访问来自接口中继承的默认方法
区别:
- 匿名内部类可以为任意接口创建实例,只要实现抽象方法即可,也可以为抽象类普通类创建实例,但是Lambda只能为函数式接口创建实例
2.匿名内部类实现的抽象方法体中允许调用接口中定义的默认方法,但Lambda表达式的代码块不允许调用接口中的默认方法
ps:接口不能创建实例new,但是可以用于声明引用类型变量,用内部类或者lambda表达式实现(implements)接口后可以赋值,他的过程是实现接口的抽象方法并且创建一个实例