Java8-Lambda表达式

Lambd

JAVA技术交流群:737698533

lambda表达式是java8的新特性,可以使用函数式接口替换掉原来的匿名内部类

lambda的本质就是引用一个已经具体实现的方法来完成对函数式接口抽象方法的具体实现

例如现在有一个接口,里面只有一个求和方法

public interface Mylambda {
    int sum(int a,int b);
}

我们现在想要使用这个方法,有三种方式

  1. 创建一个类实现这个接口
  2. 匿名内部类
  3. 使用lambda函数式接口

第一种方法就不说了,来看使用匿名内部类

Mylambda myLambda=new Mylambda() {
    @Override
    public int sum(int a, int b) {
        return a+b;
    }
};

然后调用myLambda的sum方法可以做到求和的操作

再来看看lambda

Mylambda myLambda=(int a,int b)->{
    return a+b;
};

()->{} 什么意思呢? 我们来看看lambda是如何使用的

() 里面是传入的参数

{} 里面为方法体具体操作

需要注意的点

  1. lambda只能用于只有一个方法的接口
  2. 最好在接口上添加注解@FunctionalInterface来表明这是一个函数式接口
  3. 参数类型因为已经在接口中定义,那么传入参数时可以不用写参数类型,要么参数都写参数类型,要不然都不写参数类型
  4. 参数的数量,类型,顺序必须和接口中一致

那么lambda就这些吗? 当然不是,还可以简化以及拆分方法

简化

如果方法体中就只有一条return语句,例如上面sum方法中,那么在lambda表达式中可以省略大括号以及return

public static void main(String[] args) {
    Mylambda mylambda = (a,b) -> a + b;
}

如果参数只有一个,可以省略小括号

例如下面这个接口,我们并没有做任何操作,只是将传入参数原封不动返回,只是为了学习使用

@FunctionalInterface
public interface MyLambda2 {
    int print(int i);
}

使用

public static void main(String[] args) {
    MyLambda2 myLambda2= i -> i;
}

是不是看的有点蒙呢,不简化就是

MyLambda2 myLambda2= (i) -> {
    return i;
};

因为参数只有一个,而且返回值也只有一条return语句,所以省略了传入参数的小括号以及方法体的大括号和return关键字

这里也有个需要注意的点 : 方法体的大括号和return语句要么都省略,不能只省略一个

如果方法中仅仅想返回一个对象,不做任何其他操作,还可以简化

//接口============
@FunctionalInterface
public interface MyLambda2 {
    User getUser();
}
//使用,未简化前===========
public static void main(String[] args) {
    MyLambda2 myLambda=()->{
        return  new User();
    };
}
//再根据参数和方法体简化=====
public static void main(String[] args) {
    MyLambda2 myLambda2=()->new User();
}
//使用,简化后
public static void main(String[] args) {
    MyLambda2 myLambda=User::new;
}

上面两个使用估计都可以看懂,但是最后一个User::new 估计有点蒙,什么意思呢?

在开头就讲过 lambda的本质就是引用一个已经具体实现的方法来完成对函数式接口抽象方法的具体实现

而lambda创建User对象说白了就是调用User的构造方法,而lambda调用对象的构造方法的语法就是 类型::new也就是上面写的User::new,这种方式称为构造器引用

那么如果想通过lambda调用对象的有参构造呢?

很遗憾,不能通过这种方式来调用对象的有参构造,如果想通过lambda调用,我们可以稍微简化为下面这种

//接口========
@FunctionalInterface
public interface MyLambda2 {
    User getUser(String name,int age);
}
//测试=============
public static void main(String[] args) {
    MyLambda2 myLambda2=(name,age)->new User();
}

拆分,也就是方法引用

那么如果一个方法我们经常使用该怎么办呢,难道每次都去复制原来的lambda表达式吗?

可以将常用的方法单独拆分出来,每次lambda表达式去调用这个方法即可

我们以上面的sum接口为例 :

//接口===================
@FunctionalInterface
public interface Mylambda {
    int sum(int a,int b);
}
//测试==================
public static void main(String[] args) {
    Mylambda mylambda = (a,b)-> doSum(a,b);
    int sum = mylambda.sum(2, 5);
}
//抽取出的方法( 注意是静态调用静态,如果是普通方法需要创建对象 )===============
public static int doSum(int a,int b){
    return a+b;
}

我们将求和的操作单独拆分为一个方法,每次使用时只需要调用这个方法即可

() -> xxx();

也就是说lambda不仅可以直接写方法具体细节,也可以调用其他方法,需要注意的时调用的方法返回值必须和接口定义返回值一致
当然,调用拆分的方法也可以简化,使用方法如下

静态类 类名::方法

非静态 对象::方法

对于静态的方法引用

//接口=======
@FunctionalInterface
public interface Mylambda {
    int sum(int a,int b);
}
//测试类名为Test=========
public static void main(String[] args) {
    Mylambda myLambda=Test::doSum;
}
//拆分的方法========
public static int doSum(int a,int b){
    return a+b;
}

对于非静态方法引用


//接口=======
@FunctionalInterface
public interface Mylambda {
    int sum(int a,int b);
}
//测试类名为Test=========
public static void main(String[] args) {
    Test test = new Test();
    Mylambda myLambda=test::doSum;
}
//拆分的方法========
public static int doSum(int a,int b){
    return a+b;
}

两者区别仅仅是在于对象::方法类::方法,因为非静态类需要创建出对象才可以调用方法

当使用简化后的调用方法那么会自动匹配参数类型,数量和顺序,所以更加要严谨仔细,确保参数一一对应

再说一遍吧,lambda的本质就是引用一个已经具体实现的方法来完成对函数式接口抽象方法的具体实现,那么现在再来看这句话是不是清楚很多呢

本文仅个人理解,如果有不对的地方欢迎评论指出或私信,谢谢٩(๑>◡<๑)۶

posted @ 2020-12-29 22:32  Jame!  阅读(391)  评论(0编辑  收藏  举报