文章目录
Lambda表达式
##介绍
Lambda表达式是JDK1.8的新增的重要特性,它可以极大地简化代码,使得代码更为简洁。
对于接口的实现我们有两种方式,一种是接口实现类,另一种就是匿名内部类的方式对接口作实现。lambda表达式本质上也是一个匿名内部类,常用于实现某个接口,这可以取代大部分匿名内部类。lambda表达式可以使代码更加优雅简洁,尤其是在集合的操作中可以大大优化代码结构。但要注意的是,lambda表达式实现的是函数式接口,(函数式接口就是指只有一个函数需要被实现的接口);
加上注解:@FunctionalInterface的接口就是一个函数式接口
lambda表达式语法
lambda语法结构如下:
(参数列表)->{实现函数};//因为能实现的方法只有一个,所以要求是一个函数式接口;
实例
//定义一个接口:
@FunctionalInterface
interface Test{
void method();
}
public class Test {
public static void main(String[] args) {
Test test =()->{System.out.println("Test");}
test.method();//结果为:Test
}
}
如果不是用Lambda表达式,则代码需要这样写:
public class Test {
public static void main(String[] args) {
Test test = new Test(){
public void method(){
System.out.println("Test");
}
}
test.method();//结果为:Test
}
}
由此可体会到lambda表达式带来的简洁性,与优雅性。
lambda表达式的简化
对于函数体只有一句的实现方法可以省略大括号;参数的类型可以省略,因为JVM会自动识别;
对于没有参数没有返回值的实现方法:()->{};
对于有一个参数的无返回值的实现方法:小括号可以省略,如:a->{};
对于有多个参数,无返回值情况:小括号不可以省略:(a,b)->{};
对于无参数,有返回值情况:()->{};//返回值类型省略
对于有一个参数,有返回值:a->{};
对于有多个参数,无返回值情况不能省略;
package Lamada;
/**
*无返回值,无参数;
*/
@FunctionalInterface
interface NoReturnNoPaten{
void method();
}
/**
*无返回值,一个参数
*/
@FunctionalInterface
interface NoReturnOneParen{
void method(int i);
}
/**
* 无返回值,多个参数;
*/
@FunctionalInterface
interface NoReturnManyParen{
void method(int a,int b);
}
/**
* 有返回值,无参数;
*/
@FunctionalInterface
interface ReturnNoParen{
int method();
}
/**
* 有返回值,有一个参数
*/
@FunctionalInterface
interface ReturnOneParen{
int method(int i);
}
/**
* 有返回值,有多个参数;
*/
@FunctionalInterface
interface ReturnManyParen{
int method(int a,int b);
}
public class Test {
public static void main(String[] args) {
//完整版本
NoReturnNoPaten noReturnNoPaten=()->{System.out.println("无参数无返回值");};//简化:()->System.out.print;
noReturnNoPaten.method();
NoReturnOneParen noReturnOneParen = (int a)->{System.out.println("有一个参数无返回值");};//a->...;
noReturnOneParen.method(1);
NoReturnManyParen noReturnManyParen = (int a,int b)->{System.out.println("有多个参数无返回值");};//(a,b)->...;
noReturnManyParen.method(1,2);
ReturnNoParen returnNoParen = ()->{System.out.println("没有参数有返回值");return 1;};//()->{};
returnNoParen.method();
ReturnOneParen returnOneParen = (int a)->{System.out.println("有返回值有多个参数");return a;};//a->{};
returnOneParen.method(1);
ReturnManyParen returnManyParen = (int a,int b)->{System.out.println("有多个返回和多个参数");return a+b;};//(a,b)->{};
returnManyParen.method(1,2);
}
}
lambda表达式_引用方法
有时候我们不一定要使用lambda表达式对函数进行实现,可以利用lambda表达式指向一个已经被实现好的方法;
语法:
方法归属者::方法名
其中,静态方法的归属者为类名,普通方法的归属者为类对象;
public class Test2 {
public static void main(String[] args) {
ReturnOneParen returnOneParen = a->Do(a);//在本类中实现,或者使用Test2::Do;
returnOneParen.method(10);
ReturnOneParen returnOneParen1 = Test::Do2;//在另一个类(Test类)中实现
//对于非静态的方法,则需要使用该类的一个对象即 test::Double2(double2是非静态方法);
returnOneParen.method(10);
}
public static int Do(int a){
return a;
}
}
//Test类:
public class Test {
public static void main(String[] args) {
}
public static int Do2(int a){
return a;
}
}
lambda表达式在线程中的使用:
线程的创建方式有两种,一种是继承thread类,一种是实现Runable接口,并实现run()方法;
lambda表达式可以用于替代Runable接口这种创建方法,因为lambda本质上就是来替代函数式接口实现类的,而Runale恰好就是一个函数式接口;
public class Test3 {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName()+"开始");
new Thread(()->{ System.out.println(Thread.currentThread().getName()+"balabal");},"Lamada").start();
System.out.println(Thread.currentThread().getName()+"结束");
}
}
lambda操作集合
遍历集合:
//我们可以通过调用集合的public void forEach (Consumer<? super E>action)方法,通过lambda表达式的方式遍历集合中的元素。Consumer接口是JDK提供的一个函数式接口;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
/**
* 自己定义接口的方式;
*/
class ConsumerInput implements Consumer{
@Override
public void accept(Object o){
System.out.println(o);
}
}
public class Test4 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
ConsumerInput c=new ConsumerInput();//这是自己定义接口的方式
list.forEach(System.out::println);//lambda表达式的形式
}
}
删除结合中的元素
//我们可以通过public boolean void removeIf(Predicate<? super E>filter)方法来删除集合中的元素;Predicate是jdk提供的一个函数式接口;
public class Test5 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
//删除b元素
list.removeIf(ele->{ele.equals("b");});//lambda表达式的形式,ele为参数
}
}
对集合中的元素进行排序;
public class Test6 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.sort((o1,o2)->{
return o1.compareTo(o2);
});
}
}
补充:
注意
lambda表达式中访问的局部变量,只能是常量类型,在后续中如果对被访问的局部变量进行修改编译器会报错,这是因为匿名内部类中的局部变量只能是常量类型;
为什么局部变量不能而静态变量可以,存在于栈中,不能被不同的线程共享,而静态变量存在于堆中,是可以被共享的,不同的线程可以访问该变量。
匿名内部类;
对于匿名内部类,匿名指没有名字,也不用class关键字的类,内部,指在一个类中定义的类,一般只用一次。匿名内部类其多用做创建某个接口类型的对象时使用。
其语法结构如下:
new 父类构造器(参数类标或者实现接口){
//主体部分;
}