Lambda表达式(全面探究)

Lambda表达式是JDK8引入的新特性,它简化了函数式接口的实现,常用于集合操作。文章详细介绍了函数式接口的概念,Lambda表达式的基础语法,包括参数列表和方法体的编写,以及参数部分的精简。同时,文章还讲解了函数引用,包括静态方法、非静态方法和构造方法的引用,以及对象的特殊引用。最后,提到了Lambda表达式中关于局部变量的闭包行为。
摘要由CSDN通过智能技术生成

Lambda表达式简介

        Lambda 表达式是 JDK8 的一个新特性,可以取代大部分的匿名内部类,写出更简洁的 Java 代码,尤其在集合的遍历和其他集合操作中,可以极大地优化代码结构。
       JDK 也提供了大量的内置函数式接口供我们使用,使得 Lambda 表达式的运用更加方便、高效。

1.函数式接口

基础概念:

        如果一个接口中,要求实现类必须实现的抽象方法,有且只有一个!!!这样的接口就是函数式接口。

        可以使用@FunctionalInterface注解来确定该接口是不是函数式接口,不是函数式接口使用这个注解会报错。

public class FunctionalInterface{
    //这个接口只有一个方法并且是必须实现的,是函数式接口
    @FunctionalInterface
    interface Test1{
        void test();
    }

    //这个接口有两个必须实现的方法!!!不是函数式接口
    @FunctionalInterface
    interface Test2{
        void test1();
        void test2();
    }

    //这个接口有0个必须实现的方法!!!不是函数式接口
    @FunctionalInterface
    interface Test3{ }

    //这个接口没有必须实现的方法,但是通过继承Test1接口,得到一个父接口的抽象方法,所以是函数式接口
    @FunctionalInterface
    interface Test4 extends Test1{}

    //这个接口有两个方法,default方法子类并不是必须实现的,除此之外有一个必须实现的抽象方法,所以是函数式接口
    @FunctionalInterface
    interface Test5 {
        void test5();
        default void test() {

        }
    }

    //这个接口中有toString方法,是Object类定义的方法
    //实现类在实现接口的时候toString是可以不重写的,因为可以从父接口继承,所以这个方法不是必须实现的
    //这个toString方法之外只有一个必须实现的抽象方法,所以是函数式接口
    @FunctionalInterface
    interface Test6{
        void test6();
        String toString();
    }
}

2. Lambda表达式的基础语法

说了函数式接口,就是因为Lambda只能简化函数式接口的实现。

lambda表达式本质来说就是一个匿名函数,因此在写lambda表达式的时候,不需要关系方法名是什么 实际上,我们在写lambda表达式的时候,也不需要关心返回值类型 我们只需要关注两个部分内容即可: 参数列表和方法体

2.1 基础语法:

(参数) ->{
     方法体 
}; 

参数部分 : 方法的参数列表,要求和实现的接口中的方法参数部分一致,包括参数的数量和类型。 方法体部分 : 方法的实现部分,如果接口中定义的方法有返回值,则在实现的时候,注意返回值的返回。

->: 分隔参数部分和方法体部分。

下面列出各种有参或无参,有返回值或无返回值的Lambda表达式的实现

接口准备:


//无参,没有返回值的函数式接口
@FunctionalInterface
interface NoneReturnNoneParameter {
    void test();
}
//一个参数,没有返回值的函数式接口
@FunctionalInterface
interface NoneReturnSingleParameter {
    void test(int a);
}
@FunctionalInterface
//多个参数,没有返回值的函数式接口
interface NoneReturnMultipleParameter {
    void test(int a,int b);
}

@FunctionalInterface
//无参数,有返回值的函数式接口
interface SingleReturnNoneParameter {
    int test();
}
@FunctionalInterface
//有一个参数,有返回值的函数式接口
interface SingleReturnSingleParameter {
    int test(int a);
}
@FunctionalInterface
//有多个参数,有返回值的函数式接口
interface SingleReturnMultipleParameter {
    int test(int a,int b);
}

Lambda表达式实现:

 public static void main(String[] args) {
        // 1.实现无参数,无返回值的函数式接口
        NoneReturnNoneParameter lambda1 = () -> {
            System.out.println("这是一个无参,无返回值的方法");
        };
        lambda1.test();
        // 2.实现一个参数,无返回值的函数式接口
        NoneReturnSingleParameter lambda2 = (int a) -> {
            System.out.println("这是一个参数,无返回值的方法,参数a:" + a);
        };
        lambda2.test(10);
        // 3,实现多个参数,无返回值的函数式接口
        NoneReturnMultipleParameter lambda3 = (int a, int b) -> {
            System.out.println("这是多个参数,无返回值的方法,参数 a:" + a + "b =" + b);
        };
        lambda3.test(100, 200);

        // 4,实现无参,有返回值的函数式接口
        SingleReturnNoneParameter lambda4 = () -> {
            System.out.println("这是无参数,有返回值的方法,返回值是:"+ 10);
            return 10;
        };
        int ret1 = lambda4.test() ;
        System.out.println(ret1);

        // 5.实现一个参数,有返回值的函数式接口
        SingleReturnSingleParameter lambda5 = (int a) -> {
            System.out.println("这是一个参数,有返回值的方法,返回值是:" + a);
            return a;
        };
        int ret2 = lambda5.test(100);
        System.out.println(ret2);

        // 6.实现多个参数,有返回值的函数式接口
        SingleReturnMultipleParameter lambda6 = (int a,int b) -> {
            System.out.println("这是多个参数,有返回值的方法");
            return a + b;
        };
        int ret3 = lambda6.test(100,200);
        System.out.println(ret3);
}

2.2参数部分的精简

 
参数的类型
由于在接口的方法中,已经定义了每一个参数的类型是什么。而且在使用lambda表达式实现接口的时候,必须要保证参数的数量和类型需要和接口中的方法保持一致。因此,此时lambda表达式中的参数的类型可以省略不写。

注意事项:
如果需要省略参教的类型,要保证:要省略,每一个参数的类型都必须省略不写。绝对不能出现,有的参数类型省略了,有的参教类型没有省略。

//      多个参数、无返回值的方法实现   
        NoneReturnMultipleParameter lambda8 = (a, b) ->
        System.out.println("多个参数、无返回值的方法实现 a = " + a + ", b = " + b);
参数的小括号
如果方法的参数列表中的参数数量 有且只有一个 ,此时,参数列表的小括号是可以省略不写的。

注意事项:
只有当参数的数量是一个的时候,多了、少了都不能省略
省略掉小括号的同时,必须要省略参数的类型。
//      有参、无返回值的方法实现
        NoneReturnSingleParameter lambda9 = (a) ->{
            System.out.println("一个参数、无返回值的方法实现 参数是 " + a);
        };

3. 函数引用

lambda表达式是为了简化接口的实现的。在lambda表达式中,不应该出现比较复杂的逻辑。如果在lambda表达式中出现了过于复杂的逻辑,会对程序的可读性造成非常大的影响。 如果在lambda表达式中需要处理的逻辑比较复杂,一般情况会单独的写一个方法。在lahda表达式中直接引用这个方法即可。


或者,在有些情况下,我们需要在lambda表达式中实现的逻辄,在另外一个地方已经写好了。此时我们就不需要再单独写一遍,只需要直接引用这个已经存在的方法即可。


函数引用:引用一个已经存在的方法,使其替代lambda表达式完成接口的实现。

3.1 静态方法的引用

语法:
类::静态方法


注意事项:
1. 在引用的方法后面,不要添加小括号。
2. 引用的这个方法,参数(数量、类型) 和 返回值,必须要跟接口中定义的一致。

public class Lambda1 {
    static interface Calculate {
        int calculate(int a, int b);
    }
    public static void main(String[] args){
//        Calculate calculate = (x,y) -> calculate(x,y);
//        简化 --->
        Calculate calculate1 = Lambda1::calculate;
        System.out.println(calculate1.calculate( 10, 20));

    }
    private static int calculate(int x, int y) {
        if (x > y)
            return x - y;

        else if (x < y)
            return y - x;

        return x + y;

    }

3.2 非静态方法的引用

语法:
对象::非静态方法


注意事项:
1.在引用的方法后面,不要添加小括号。
2.引用的这个方法,参数(数量、类型) 和 返回值,必须要跟接口中定义的一致。

public class Syntax2{
    public static void main(String[] args){
        // 对非静态方法的引用,需要使用对象完成
        SyngleReturnMuitpleParamenter lambda = new Calculator()::calculate;
        System.out.println(lambda.test(10,30));
    }
    private static class Calculator{
        public int calculate(int a,int b{
            return a > b ? a - b : b - a;    
        }    
    }

}

3.3 构造方法的引用

使用场景。如果某一个函数式接口中定义的方法,仅仅是为了得到一个类的对象。此时我们就可以使用构造方法的引用,简化这个方法的实现。语法
。类名::new
。注意事项
。可以通过接口中的方法的参数,区分引用不同的构造方法。

package Lamdba_xuexi;

public class Lambda_xue2 {
    private interface GetPersonWithNoneParameter{
        Person get();
    }
    private interface GetPersonWithSingleParameter{
        Person get(String name);
    }
    private interface GetPersonWithMutipleParameter{
        Person get(String name,int age);
    }


    public static void main(String[] args) {

        //1,使用lambda表达式,实现GetPersonWithNoneParameter接口
        GetPersonWithNoneParameter getPerson = Person::new;
        //2.使用lambda表达式,实现GetPersonWithSingleParameter接口
        GetPersonWithSingleParameter getPerson2 = Person::new;
        //3.使用lambda表达式,实现GetPersonWithMutipleParameter接口
        GetPersonWithMutipleParameter getPerson3 = Person::new;
        Person person = getPerson.get();
        getPerson2.get("");
        getPerson3.get( "", 1);




        GetPerson getPerson4 = Person::new;
        Person qwe1 = getPerson4.get("jack",21);
        System.out.println(qwe1.toString());

//      以上语句相当于创建了一个类实现了GetPerson1接口并且创建这个类调用方法
//
//        GetPersonObject c = new GetPersonObject();
//        Person qwe2 = c.get("tom",18);
//        System.out.println(qwe2.toString());

    }

}
 class Person{
    int age;
    String name;

     public Person(String s) {
     }

     @Override
     public String toString() {
         return "Person{" +
                 "age=" + age +
                 ", name='" + name + '\'' +
                 '}';
     }

     public Person(String name, int age) {
         this.age = age;
         this.name = name;
         System.out.println("2个参数的构造方法调用了");
     }
     public Person(){
         System.out.println("无参的构造方法调用了");
     }
     public Person(int age) {
         this.age = age;
         System.out.println("1个参数的构造方法调用了");
     }


 }

 class GetPersonObject implements GetPerson{
     @Override
     public Person get(String name, int age) {
         return new Person(name,age);
     }
 }

interface GetPerson{
    Person get(String name ,int age);
}


3.3 对象的特殊引用

如果在使用lambda表达式,实现某些接口的时候。lambda表达式中包含了某一个对象,此时方法体中,直接使用这个对象调用它的某一个方法就可以完成整体的逻辑。其他的参数,可以作为调用方法的参数。此时,可以对这种实现进行简化。

package Lamdba_xuexi;

public class Syntax {

    public static void main(String[] args) {
        // 如果对于这个方法的实现逻辑,是为了获取到对象的名字
        GetField field = person -> person.getName();
        // 对于对象方法的特殊引用
        GetField field2 = Person::getName;

        // 如果对于这个方法的实现逻辑,是为了给对象的某些属性进行赋值
        SetField lambda = (person, name) -> person.setName(name);
        SetField lambda2 = Person::setName;

        // 如果对于这个方法的实现逻辑,正好是参数对象的某一个方法
        ShowTest lambda3 = person -> person.show();
        ShowTest lambda4 = Person::show;

        ShowTest2 lambda5 = (person,a,b) -> person.show(a,b);
        ShowTest2 lambda6 = Person::show;
    }
    interface ShowTest2 {
        void test(Person person,int a,int b);
    }
    interface ShowTest {
        void test(Person person);
    }

    interface SetField {
        void set(Person person, String name) ;
    }

    interface GetField {
        String get(Person person) ;
    }



}


class Person{
    public void show(int a, int b) {

    }

    public void show() {
    }
    int age;
    String name;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Person(String s) {
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }

    public Person(String name, int age) {
        this.age = age;
        this.name = name;
        System.out.println("2个参数的构造方法调用了");
    }
    public Person(){
        System.out.println("无参的构造方法调用了");
    }
    public Person(int age) {
        this.age = age;
        System.out.println("1个参数的构造方法调用了");
    }



}

4.Lambda表达式注意细节

当局部变量被一个代码段引用的时候,形成一个闭包。此时的局部变量被默认是final类型的值
package Lamdba_xuexi;

public class LambdaAttention {
    static int y = 10;
    public static void main(String[] args) {
        int x = 10;
        LambdaTest lambda = () ->{
            System.out.println("x = " + x);
            System.out.println("y = " + y);
        };
//        x = 1; 当局部变量被一个代码段引用的时候,形成一个闭包。此时的局部变量被默认是final类型的值
        y = 1; //这里修改静态属性却没有影响
    }
}

interface LambdaTest{
    void test();
}

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值