Java中的Lambda表达式

125 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

前言:Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。使用它可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。 代码举例:

    @Test
    public void test1(){

        //匿名实现类的非匿名对象
        Runnable runnable = new Runnable(){

            @Override
            public void run() {
                System.out.println("This is test");
            }
        };

        runnable.run();


        //Lambda表达式
        Runnable runnable1 = () -> System.out.println("This is test");

        runnable1.run();
    }

输出结果:

This is test
This is test

Process finished with exit code 0

相信初学者看到这里会有所不明白,那么下面我们将详细说明Lambda表达式。

一.Lambda表达式的语法

在Java 8 语言中引入了一种新的语法元素和操作符。这个操作符为 “->” , 该操作符被称为 Lambda 操作符或箭头操作符。它将 Lambda 分为两个部分:

  • 左侧:指定了 Lambda 表达式需要的参数列表
  • 右侧:指定了 Lambda 体,是抽象方法的实现逻辑,也即 Lambda 表达式要执行的功能。

Lambda表达式的本质是作为函数式接口的实例。

1. 无参,无返回值

    @Test
    public void test1(){
        Runnable runnable = new Runnable() {

            @Override
            public void run() {
                System.out.println("This is test!!!");
            }
        };

        //1. 无参,无返回值
        Runnable runnable1 = () -> {
            System.out.println("This is test!");
        };
    }

2.有一个参数,但是没有返回值。

    @Test
    public void test2(){

        Consumer<String> consumer = new Consumer<>() {

            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };

        //2.有一个参数,但是没有返回值。
        Consumer<String> consumer1 = (String s) -> {
            System.out.println(s);
        };
    }

3.数据类型可以省略,因为可由编译器推断得出(类型推断)

    @Test
    public void test2(){

        Consumer<String> consumer = new Consumer<>() {

            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };

        //2.有一个参数,但是没有返回值。
        Consumer<String> consumer1 = (String s) -> {
            System.out.println(s);
        };

        //3.数据类型可以省略,因为可由编译器推断得出(类型推断)
        Consumer<String> consumer2 = (s) -> {
            System.out.println(s);
        };
    }

4.Lambda 若只需要一个参数时,参数的小括号可以省略

    @Test
    public void test2(){

        Consumer<String> consumer = new Consumer<>() {

            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };

        //2.有一个参数,但是没有返回值。
        Consumer<String> consumer1 = (String s) -> {
            System.out.println(s);
        };

        //3.数据类型可以省略,因为可由编译器推断得出(类型推断)
        Consumer<String> consumer2 = (s) -> {
            System.out.println(s);
        };

        //4.Lambda 若只需要一个参数时,参数的小括号可以省略
        Consumer<String> consumer3 = s ->{
            System.out.println(s);
        };
    }

5.Lambda 需要两个或以上的参数,多条执行语句,并且可以有返回值

    @Test
    public void test3(){
        Comparator<Integer> comparator = new Comparator<>() {

            @Override
            public int compare(Integer o1, Integer o2) {
                System.out.println("函数式接口方法!");
                return Integer.compare(o1, o2);
            }
        };

        //5.Lambda 需要两个或以上的参数,多条执行语句,并且可以有返回值
        Comparator<Integer> comparator1 = (x,y) -> {
            System.out.println("函数式接口方法!");
            return Integer.compare(x,y);
        };
        
    }

6.当 Lambda 体只有一条语句时,return 与大括号若有,都可以省略

    @Test
    public void test3(){
        Comparator<Integer> comparator = new Comparator<>() {

            @Override
            public int compare(Integer o1, Integer o2) {
                System.out.println("函数式接口方法!");
                return Integer.compare(o1, o2);
            }
        };

        //5.Lambda 需要两个或以上的参数,多条执行语句,并且可以有返回值
        Comparator<Integer> comparator1 = (x,y) -> {
            System.out.println("函数式接口方法!");
            return Integer.compare(x,y);
        };

        //6.当 Lambda 体只有一条语句时,return 与大括号若有,都可以省略
        
        // 6.1
        Comparator<Integer> comparator2 = (x,y) -> {
            return Integer.compare(x,y);
        };
        //6.2 
        Comparator<Integer> comparator3 = (x,y) -> Integer.compare(x,y);

    }
    @Test
    public void test2(){

        Consumer<String> consumer = new Consumer<>() {

            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };

        //2.有一个参数,但是没有返回值。
        Consumer<String> consumer1 = (String s) -> {
            System.out.println(s);
        };

        //3.数据类型可以省略,因为可由编译器推断得出(类型推断)
        Consumer<String> consumer2 = (s) -> {
            System.out.println(s);
        };

        //4.Lambda 若只需要一个参数时,参数的小括号可以省略
        Consumer<String> consumer3 = s ->{
            System.out.println(s);
        };

        //6.当 Lambda 体只有一条语句时,return 与大括号若有,都可以省略
        Consumer<String> consumer4 = s -> System.out.println(s);

    }

二.类型推断说明

上述 Lambda 表达式中的参数类型都是由编译器推断得出的。Lambda 表达式中无需指定类型,程序依然可以编译,这是因为 javac 根据程序的上下文,在后台推断出了参数的类型。Lambda 表达式的类型依赖于上下文环境,是由编译器推断出来的。这就是所谓的“类型推断”。 例如:

Consumer<String> consumer = new Consumer<>() {

    @Override
    public void accept(String s) {
        System.out.println(s);
    }
};

//数据类型可以省略,因为可由编译器推断得出(类型推断)
Consumer<String> consumer2 = (s) -> {
    System.out.println(s);
};

三.Lambda表达式与函数式接口

  • Java从诞生日起就是一直倡导“一切皆对象”,在Java里面面向对象(OOP) 编程是一切。但是随着python、scala等语言的兴起和新技术的挑战,Java不 得不做出调整以便支持更加广泛的技术要求,也即java不但可以支持OOP还 可以支持OOF(面向函数编程)。在函数式编程语言当中,函数被当做一等公民对待。在将函数作为一等公民的 编程语言中,Lambda表达式的类型是函数。但是在Java8中,有所不同。在 Java8中,Lambda表达式是对象,而不是函数,它们必须依附于一类特别的 对象类型——函数式接口。
  • 简单的说,在Java8中,Lambda表达式就是一个函数式接口的实例。这就是 Lambda表达式和函数式接口的关系。也就是说,只要一个对象是函数式接口的实例,那么该对象就可以用Lambda表达式来表示。所以以前用匿名实现类表示的现在都可以用Lambda表达式来写。