Lambda表达式

100 阅读6分钟

函数式编程

什么是函数式编程

1·概念:

面向对象思想需要关注用什么对象完成什么事情。
而函数式编程思想就类似于我们数学中的函数,它主要关注的是对数据进行了什么操作。

2·优点:

• 代码简洁,开发快速</b>
    
• 接近自然语言,易于理解</b>
    
• 易于“并发编程”</b>

Lambda表达式

小实现

package lambda3;
/**
 * @program: src
 * @description: 定义一个计算接口,只有一个方法add
 * @author: SongZhiZe
 * @create: 2022-10-23 12:51
 **/
public class Program {
//    定义接口-规范
    interface Cal{
        int add(int a,int b);
    }
    public static void main(String[] args) {
//      实现类-实现操作
/*
    没有用Lambda实现的匿名内部类
     Cal c = new Cal(){
//            方法实现
            @Override
            public int add(int a, int b) {
                return a+b;
            }
        };
*/
        Cal c = (int a,int b)->{
            return a+b;
        };
        System.out.println(c.add(1, 2));

    }
}

概述

Lambda是JDK8中一个语法糖。可以看成一种语法糖,他可以对某些匿名内部类的写法进行简化。它是函数式编程思想的一个重要体现。然我们不用关注是什么对象。而是更加关注我们对数据进行了什么操作,使用它设计的代码会更加简洁,通过Lambda表达式,可以替代我们以前常用的匿名内部类来实现接口。 Lambda表达式的本质就是一个匿名函数;

表达式语法

我们看下这个Lambda表达式: (int a,int b)->{return a+b;};

本质是一个函数

一般的函数类:

int add (int a,int b){
    return a+b;
    }

有返回值,有方法名,参数列表,方法体

Lambda表达式函数的话,只有参数列表和方法体;

(参数列表)->{方法体}

说明:

  1. ()用来描述参数列表;
  2. {}用来描述方法体;
  3. -> Lambda运算符,可以叫做箭头符号,或者goes to

Lambda表达式语法精讲

我们通过一个案例,接口方法参数,无参,单个参数,两个参数,没有返回值,这六种情况来了解Lambda表达式

package lambda3;

/**
 * @program: src
 * @description: 语法精讲
 * @create: 2022-10-23 13:21
 **/
public class Program1 {
    /*无参数无返回值*/
    interface IF1 {
        void test();
    }

    /*单个参数无返回值*/
    interface IF2 {
        void test(int a);
    }

    /*两个参数无返回值*/
    interface IF3 {
        void test(int a, int b);
    }

    /*无参数有返回值*/
    interface IF4 {
        int test();
    }

    /*单个参数有返回值*/
    interface IF5 {
        int test(int a);
    }

    /*多个参数有返回值*/
    interface IF6 {
        int test(int a, int b);
    }

    public static void main(String[] args) {
        IF1 if1 = () -> {
            System.out.println("无参数无返回值");
        };
//        调用方法
        if1.test();
        System.out.println("----------------------");
        IF2 if2 = (int a) -> {
            System.out.println("单个参数无返回值  a=" + a);
        };
        if2.test(3);
        System.out.println("----------------------");
        IF3 if3 = (int a, int b) -> {
            System.out.println("两个参数无返回值  a+b=" + (a + b));
        };
        if3.test(12, 10);
        System.out.println("----------------------");
        IF4 if4=()->{
            return 4;
        };
        System.out.println("无参数有返回值    "+if4.test());
        System.out.println("----------------------");
        IF5 if5=(int a)->{
            return a;
        };
        System.out.println("单个参数有返回值   "+if5.test(5));
        System.out.println("----------------------");
        IF6 if6=(int a,int b)->{
            return a*b;
        };
        System.out.println("两个参数有返回值   "+if6.test(10,20));
    }
}

Lambda表达式精简语法

注意:

  • 参数类型可以省略
  • 假如只有一个参数,()可以省略
  • 如果方法体只有一条语句,{}可以省略
  • 如果方法体中唯一的语句是return返回语句,那省略大括号的同时return也要省略

实例改写:


package lambda3;

/**
 * @program: src
 * @description: 精简语法
 * @create: 2022-10-23 13:21
 **/
public class Program2 {
    /*无参数无返回值*/
    interface IF1 {
        void test();
    }

    /*单个参数无返回值*/
    interface IF2 {
        void test(int a);
    }

    /*两个参数无返回值*/
    interface IF3 {
        void test(int a, int b);
    }

    /*无参数有返回值*/
    interface IF4 {
        int test();
    }

    /*单个参数有返回值*/
    interface IF5 {
        int test(int a);
    }

    /*多个参数有返回值*/
    interface IF6 {
        int test(int a, int b);
    }

    public static void main(String[] args) {
//        方法体只有一条语句,{}可以省略
        IF1 if1 = () -> System.out.println("无参数无返回值");
//        调用方法
        if1.test();
        System.out.println("----------------------");
//        参数类型省略,一个参数,小括号省略,一条语句{}省略
        IF2 if2 = a -> System.out.println("单个参数无返回值  a=" + a);
        if2.test(3);
        System.out.println("----------------------");
        IF3 if3 = ( a,  b) -> System.out.println("两个参数无返回值  a+b=" + (a + b));
        if3.test(12, 10);
        System.out.println("----------------------");
        IF4 if4=()->4;
        System.out.println("无参数有返回值    "+if4.test());
        System.out.println("----------------------");
//        一个参数,小括号省略
        IF5 if5= a ->a;
        System.out.println("单个参数有返回值   "+if5.test(5));
        System.out.println("----------------------");
        IF6 if6=( a, b)->a*b;
        System.out.println("两个参数有返回值   "+if6.test(10,20));
    }
}

方法引用

有时候多个lambda表达式实现函数是一样的话,我们可以封装成通用方法,从而有利于维护;

这时候可以用方法引用实现:

语法是:对象::方法

假如是static方法,可以直接 类名: :方法

实例如下

package lambda3;

/**
 * @program: src
 * @description: 方法引用
 * @author: SongZhiZe
 * @create: 2022-10-23 13:21
 **/
public class Program3 {
    /*单个参数有返回值*/
    interface IF5 {
        int test(int a);
    }

    /*非静态方法*/
    public  int testA(int a){
        return a-2;
    }

    /*静态方法*/
    public  static int testB(int a){
        return --a;
    }

    public static void main(String[] args) {
/*      非静态方法
        Program3  program3 = new Program3();
        IF5 if5 = program3::testA;
        System.out.println(if5.test(3));

        IF5 if51 =program3::testA;
        System.out.println(if51.test(5));

        */
//          静态方法
        IF5 if5 = Program3::testB;
        System.out.println(if5.test(3));

        IF5 if51 =Program3::testB;
        System.out.println(if51.test(5));


/*

        IF5 if5= a-> a-2;
        System.out.println(if5.test(3));

        IF5 if51=a-> a-2;
        System.out.println(if5.test(5));

*/
    }
}

Lambda表达式的实际应用

package lambda3.example;

/**
 * @program: src
 * @description: 定义的Dog实体类
 * @create: 2022-10-23 22:06
 **/
public class Dog {
    private String name;
    private int age;
    public Dog(){
        System.out.println("无参构造方法");
    }

    public Dog(String name, int age) {
        System.out.println("有参构造方法");
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

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

package lambda3.example;

/**
 * @program: src
 * @description:
 * @create: 2022-10-23 13:21
 **/
public class Program4 {
    //        定义两个接口
    interface DogService{
        Dog getDog();
    }
    interface DogService2{
        Dog getDog(String name,int age);
    }

    public static void main(String[] args) {
/*        DogService dogService=()-> new Dog();
//        无名无姓的dog
        System.out.println(dogService.getDog());*/
        DogService dogService= Dog::new;
//        无名无姓的dog
        System.out.println(dogService.getDog());

        DogService2 dogService2= Dog::new;
//        无名无姓的dog
        System.out.println(dogService2.getDog("王吧",3));
    }
}

通过Lambda表达式对新增的dog进行排序问题
package lambda3.example;

import java.util.ArrayList;
import java.util.function.Consumer;

/**
 * @program: src
 * @description: 综合案例
 * @author: SongZhiZe
 * @create: 2022-10-23 22:21
 **/
public class Program5 {
    public static void main(String[] args) {
        ArrayList<Dog> list = new ArrayList<>();
        list.add(new Dog("a", 1));
        list.add(new Dog("b", 5));
        list.add(new Dog("c", 4));
        list.add(new Dog("d", 3));
        list.add(new Dog("e", 2));
        System.out.println("lambda表达式集合排序");
        list.sort((o1, o2) -> o1.getAge() - o2.getAge());
        System.out.println("lambda表达式遍历集合");

        /*  下面是三种相同的遍历方法 */
//        list.forEach(System.out::println);
/*        list.forEach(
                x->{
                    System.out.println(x);
                }
        );*/
        list.forEach(
                new Consumer<Dog>() {
                    @Override
                    public void accept(Dog x) {
                        System.out.println(x);
                    }
                }
        );
    }
}

@FunctionalInterface 注解

在前面我们会发现Comsumer接口,Comparator接口都有@FunctionalInterface注解:

这个注解是函数式接口注解,所谓的函数式接口,首先是一个接口,然后在这个接口里面只有一个抽象方法。

这种类型的接口也称之为SAM接口,即Single Abstract Method interfaces

特点

  • 接口有且仅有一个抽象方法
  • 允许定义静态方法
  • 允许定义默认方法
  • 允许java.lang.Object中的public方法
  • 该注解不是必须的,如果一个接口符合“函数式接口”定义,那么加不加该注解都没有影响。加上该注解能够更好的让编译器进行检查,如果编写的不是函数式接口,但是加上该注解的话编译器会报错。

实例

package lambda3;

/**
 * @program: src
 * @description: @FunctionalInterface 注解
 * @author: SongZhiZe
 * @create: 2022-10-23 22:21
 **/
public class Program6 {
//    正确的函数式接口
    public interface TestInterface{

//        抽象方法
    public void sub();

//    java.lang.Object中的public方法
    public boolean equals(Object varl);

//    默认方法
    public default void defaultMethod(){}

//        静态方法
    public static void staticMethod(){}
    }

//  错误的函数式接口(有多个抽象方法)
@FunctionalInterface
    public interface  TestInterface2{
        void add();

//        void sub();
    }
}

系统内置函数式接口

java8的退出,是以Lambda重要特性,一起退出的,其中修通内置了一系列函数式接口;

在jdk的java.util.function包下,有一些列的内置函数式接口:

image.png

好啦,小编今天的分享就结束啦,希望可以帮助到大家。