lambda 表达式之美

本贴最后更新于 1508 天前,其中的信息可能已经时异事殊

背景

2020 年 9 月 27 日,我开始成为了一个社畜,同级的同学都在考研、保研、考公务员、考事业单位等等为各种考试准备着,这一路有很多很多的老师都劝过我考研,可是我还是决定做一个码农。然而我进入了九机科技。然后去了之后在熟悉项目的过程中我发现一个有趣的问题,就是在项目中使用了较多的 lambda 和 Stream 流操作,所以准备学习一下。前几天因为睡觉、逛街各种事情耽误了,但一想好久没有更新博客了,所以还是准备写一下。

简介

lambda 表达式是在 java8 中新增加的新特性,lambda 表达式其实就是一个匿名函数,有助于帮助开发者对一个接口更好的实现,也可以理解为 lambda 表达式就是用来实现接口中的抽象方法。

基础语法

因为 lambda 是一个匿名函数,而对于一个方法需要关注他的名称、参数类型、个数,返回值。但是由于它是匿名函数,所以对于 lambda 表达式来说就不需要关注他的名称,对于放回值类型也可以省略

  • 语法

    ( )  ->  {  }
    --------------------------------------------------
    ( ) : 用来描述参数列表
    { } : 用来描述方法体
    -> : lambda运算符, goes to
    
  • lambda 语法精简

1:在接口中参数的类型已经限制,所以可以省略(PS:要么全部省略,要么全写)
2:如果参数只有一个,则()可以省略
3:如果方法只有一句代码{}可以省略
4:如果方法体中唯一语句是 return,则省略{}的同时省略 return

lambda 语法实现与语法精简

import org.junit.Test;

public class Demo02 {

    //无精简的普通语法讲解
    @Test
    public void main1(){
        //无参无返回
        NoReturnNoParam lambda1 = ()->{
            System.err.println("无参无放回的lambda简单应用");
        };

        //一个参数无返回
        NoReturnSingleParam lambda2 = (int a)->{
            System.err.println("一个参数无返回,参数:"+a);
        };

        //多个参数无返回
        NoResturnSomeParam lambda3 = (int a, int b, int c)->{
            System.err.println("多个参数无返回,参数:"+a+" "+b+" "+c);
        };

        //无参数有返回
        ReturnNoParam lambda4 = ()->{return 100;};


        //一个参数有返回
        ReturnSingleParam lambda5 = (int a)->{ return a+100;};

        //多个参数有返回
        ReturnSomeParam lambda6 = (int a, int b, int c)->{
          return a + b+ c;
        };

        lambda1.test();
        lambda2.test(666);
        lambda3.test(666,888,999);
        System.err.println(lambda4.test());
        System.err.println(lambda5.test(66));
        System.err.println(lambda6.test(1,2,3));

    }


    //精简过的语法
    @Test
    public void mian2(){

        //无参无返回
        NoReturnNoParam lambda1 = ()->System.err.println("无参无放回的lambda简单应用");


        //一个参数无返回
        NoReturnSingleParam lambda2 = a->System.err.println("一个参数无返回,参数:"+a);


        //多个参数无返回
        NoResturnSomeParam lambda3 = (a,b,c)->System.err.println("多个参数无返回,参数:"+a+" "+b+" "+c);

        //无参数有返回
        ReturnNoParam lambda4 = ()->100;


        //一个参数有返回
        ReturnSingleParam lambda5 = a->a+100;

        //多个参数有返回
        ReturnSomeParam lambda6 = (a,b,c)->a + b+ c;

        lambda1.test();
        lambda2.test(66);
        lambda3.test(66,88,99);
        System.err.println(lambda4.test());
        System.err.println(lambda5.test(6));
        System.err.println(lambda6.test(1,2,3));

    }

}

//无参数,无返回
@FunctionalInterface
interface NoReturnNoParam{
    void test();
}

//无返回单参数
@FunctionalInterface
interface NoReturnSingleParam{
    void test(int a);
}

//无返回多参数
@FunctionalInterface
interface  NoResturnSomeParam{
    void test(int a, int b,int c);
}

//有返回值无参数
@FunctionalInterface
interface ReturnNoParam{
    int test();
}

//有返回值,单参数
@FunctionalInterface
interface ReturnSingleParam{
    int test(int a);
}

//有返回多参数
@FunctionalInterface
interface ReturnSomeParam{
    int test(int a, int b, int c);
}
  • lambda 语法进阶
    • 方法引用
      当在不同的地方采用的实现是一样的,则使用方法引用
    • 语法 : ::
      eg: 方法的隶属者::方法名

      方法是静态则引用则采用类名
      (Class::Method)
      方法的非静态应用采用对象
      (Object::Method)

    • PS:参数类型与返回值以及个数要一致

lambda 方法引用代码实现

public class Demo03 {
    public static void main(String[] args){

        //引用IsMax方法
        TestInterface test = Demo03::isMax;
        System.err.println(test.testBoolean(1,2));
    }

    static boolean isMax(int a, int b){
        return a > b ? true:false;
    }
}
interface TestInterface{
    boolean testBoolean(int a,int b);
}
  1. 构造方法的引用
    在接口方法中返回了某个类的对象

    构造方法引用 lambda 表达式实现

public class Demo04 {
    public static void main(String[] args){
        CreatePerson person = () -> new Person();

        //构造方法的引用
        CreatePerson person1 = Person::new;
        person1.getPerson();
        CreatePerson2 person2 = Person::new;
        person2.getPerson(18,"sirwsl");

    }

}

interface CreatePerson{
    Person getPerson();
}
interface CreatePerson2{
    Person getPerson(int age,String name);
}

class Person{
    int age;
    String name;

    public Person() {
        System.err.println("person无参构造方法已经被执行");
    }

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
        System.err.println("person带参数构造方法已经被执行");
    }

}

接口

优: 使用 lambda 可以使得一个接口进行非常简洁的实现
PS: lambda 表达式可以对某些接口进行简单的实现,但是并不是可以对所有接口进行实现。(接口中要实现的抽象方法只能是一个,不能被 default 修饰)
PS: @FunctionalInterface 修饰函数式接口,接口中抽象方法只能有一个

lambda 对接口的实现

/**
 * lambda对接口的实现
 * **/

public class Demo01 {
    public static void main(String[] args){
        //使用接口实现
        Comper comper = new MyComper();
        System.err.println(comper.compare(1,2));


        //采用匿名内部类
        Comper comper1 = new Comper() {
            @Override
            public boolean compare(int a, int b) {
                return a == b ? true:false;
            }
        };
        System.err.println(comper1.compare(1,2));


        //lambda表达式实现接口
        Comper comper2 = (a,b) -> a < b ? true:false;
        System.err.println(comper2.compare(1,2));
    }
}

class MyComper implements Comper{
    @Override
    public boolean compare(int a, int b) {
        return a > b ? true:false;
    }
}
@FunctionalInterface
interface Comper{
    boolean compare(int a, int b);
    //int test();
}

lambda 综合案例

说了这么多大概也了解了,现在我们来看几个综合案例分别是集合排序中 sort 方法实现、lambda 实现 Comparator 接口、forEach 方法实现、removeIf 方法实现

综合案例 lambda 代码实现

import org.junit.Test;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.TreeSet;

public class Demo05 {
    //ArrayList中sort实现排序
    @Test
    public void main1 (){
        //在一个ArrayList集合中存许多People对象,需要按照age进行排序
        ArrayList<People> list = new ArrayList<>();
            list.add(new People(13,"zhangsan"));
            list.add(new People(21,"lisi"));
            list.add(new People(43,"sirwsl"));
            list.add(new People(54,"test"));
            list.add(new People(12,"wangming"));
            list.add(new People(12,"miss li"));

        //lambda排序
        list.sort((o1, o2) -> o1.age-o2.age);
        //System.err.println(list.toString());
        list.forEach(System.out::println);
        list.forEach(people->{
            if (people.age>50) System.out.println("age>50 :"+people);
        });
    }

    @Test
    public void main2(){
        //用lambda表达式实现Comparator接口,并实例化一个TreeSet对象
        TreeSet<People> set = new TreeSet<>(((o1, o2) -> {
            if (o1.age<=o2.age){
                return -1;
            }else {
                return 1;
            }
        }));
            set.add(new People(21,"lisi"));
            set.add(new People(43,"sirwsl"));
            set.add(new People(54,"test"));
            set.add(new People(12,"wangming"));
            set.add(new People(12,"miss li"));
            set.add(new People(13,"zhangsan"));

        //System.out.println(set);
        set.forEach(System.out::println);

        //删除元素,非lambda实现
        /*Iterator<People> peo = set.iterator();
        while (peo.hasNext()){
            if (peo.next().age>20) peo.remove();
        }
        */

        //删除元素,lambda实现
        set.removeIf(people -> people.age>20);
        System.out.println("移除age>20结果:");
        set.forEach(System.out::println);
    }
}



class People{
    int age;
    String name;

    public People() {
    }

    public People(int age, String name) {
        this.age = age;
        this.name = name;
    }

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

lambda 线程实例化

废话不多说,直接看代码,因为好像没什么可以说的

线程实例化代码实现

public class Demo06 {
    public static void main(String[] args){

        Thread thread = new Thread(()->{
            for (int i = 0; i < 100;i++) System.err.println(i);
        });

        thread.start();
    }
}

function 函数式接口

归纳总结如下,部分没列出来,如果需要,按需枚举就可以
function 函数接口 00.png

闭包问题

在 lambda 表达式中使用闭包提升变量生命周期,使得被引用的变量在方法执行结束之后不被销毁
在 lambda 表达式中,使用变量需要保证使用的是常量,如过不是常量,在编译阶段会编译为常量,从而不能被修改
闭包问题 lambda 代码实现

import org.junit.Test;

import java.util.function.Consumer;
import java.util.function.Supplier;

public class Demo07 {
    //使用闭包延迟变量的生命周期
    @Test
    public void main1(){
        int n = getNumber().get();
        System.err.println(n);
    }
    private Supplier<Integer> getNumber(){
        int num = 100;

        return ()->{
          return num;
        };
    }


    @Test
    public void main2(){
        int a = 10;
        Consumer<Integer> c = t ->{
            System.err.println(a);
        };

        //取消a++注释则程序报错
        //a++;
        c.accept(a);

    }

}

样例打包源码

❤️ 点此处下载样例文件,lambda.zip❤️
❤️ 点此处下载样例文件,lambda.zip❤️
❤️ 点此处下载样例文件,lambda.zip❤️

  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3187 引用 • 8213 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...