这么好用的Lambda表达式,你确定不用吗?


前言

Lambda 表达式是JDK8中一个重要的特性,它使用一个清晰简洁的表达式来表达一个接口,同时Lambda表示式也简化了对集合以及数组数据的遍历、过滤和提取等操作。


一、Lambda 出现的背景

回想一下在java8之前,我们要将某些功能传递给某个方法,要怎么做?

比如我们现在要实现对一个数组元素的降序排序,有以下几种做法

1.单独写一个类实现Comparator接口

public class StringCompartor implements Comparator<String> {
    @Override
    public int compare(String o1, String o2) {
        return o2.compareTo(o1);
    }
}

使用的时候把这个类的对象传入

public class Lambda {
    public static void main(String[] args) {
        String[] arr = {"a", "b", "d", "c"};
        Arrays.sort(arr, new StringCompartor());
        System.out.println(Arrays.toString(arr));
      }
 }

在这里插入图片描述
2.使用内部类

public class Lambda {
    public static void main(String[] args) {
        String[] arr = {"a", "b", "d", "c"};
        Arrays.sort(arr, new StringCompartor());
        System.out.println(Arrays.toString(arr));
      }
      
    static class StringCompartor implements Comparator<String> {
        @Override
        public int compare(String o1, String o2) {
            return o2.compareTo(o1);
        }
    }
 }

3.使用匿名内部类
如果我们只想用一次这个功能,我们可以不用单独写个类,使用匿名内部类的方式也可以完成

public class Lambda {
    public static void main(String[] args) {
        String[] arr = {"a", "b", "d", "c"};
        Arrays.sort(arr, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o2.compareTo(o1);
            }
        });
        System.out.println(Arrays.toString(arr));
     }
  }

4.Lambda 表达式
即使匿名内部类已经帮助我们简化了很多工作,但是编写起来还不是很方便,于是lambda表达式就出现了
同样的例子代码如下:

public class Lambda {
    public static void main(String[] args) {
        String[] arr = {"a", "b", "d", "c"};
        Arrays.sort(arr,(o1,o2)->{return o2.compareTo(o1);});
        System.out.println(Arrays.toString(arr));
     }
 }

使用它可以写出更简洁, 更灵活的代码。作为一种更紧凑的代码风格,使java语言的表达式能力得到的提升。

二、Lambda 概述

Lambda 表达式是一个匿名函数,我们可以把Lambda表达式理解为一段可以传递的代码(将代码段像数据一样传递)。

语法糖(Syntactic Sugar),也称糖衣语法,指在计算机语言中添加的某种语法,这种语法对语言本身功能来说没有什么影响,只是为了方便程序员的开发,提高开发效率。

Lambda 表达式的本质只是一个"语法糖",由编译器推断并帮你转换包装为常规的代码,更少的代码实现相同的功能。

注意:这种表达式只针对有一个抽象方法的接口实现,以简洁的表达式形式实现接口功能来作为方法参数

一个Lambda表达式由三个部分组成,分别为参数列表、-- >、和表达式主体

(参数列表):向表达式主体传递接口方法需要的参数,多个参数用英文逗号进行分隔
->:表示Lambda表达式箭牌,用来指定参数数据指向,必须用英文横线和大于号书写
{表达式主体}:由单个表达式或语句块组成的主体,本质就是接口中抽象方法的具体实现。

三、函数式接口

虽然Lambda表达式可以实现匿名内部类的功能,但在使用时有一个局限,即接口中有且仅有一个抽象方法的接口。

什么是函数式接口?
函数式接口是 java 8 中的新增功能,它们只允许一个抽象方法,使用@FunctionalInterface注解

接下来通过一个案例来演示函数式接口的定义与使用

//定义无参,无返回值的函数式接口
@FunctionalInterface
interface  Animal{
    void shout();
}

//定义有参、有返回值的函数式接口
interface  Calculate{
    int sum(int a,int b);
}

public class Example {
    public static void main(String[] args) {
        //分别两个函数式接口进行测试
        animalShout(()-> System.out.println("无参、无返回值的函数式接口调用"));
        showSum(10,20,(x,y)->{ return  x+y;});
    }

    //创建一个动物叫的方法,并传入接口对象Animal作为参数
    public static void animalShout(Animal animal){
        animal.shout();
    }
    //创建一个求和的方法,并传入两个int类型以及接口Calculate类型的参数
    public  static  void showSum(int x,int y,Calculate calculate){
        System.out.println(x+"+"+y+"的和为:"+calculate.sum(x,y));
    }
}

在这里插入图片描述

注意:函数式接口只能有一个抽象方法。如果我们尝试在其中添加一个抽象方法,则会抛出编译时错误

@FunctionalInterface注解只是显式地标注了接口是一个函数式接口,并强制编辑器进行严格的检查,该注解对程序运行并没有实质上的影响。

编译器会将所有满足函数式接口要求的接口视为函数式接口,而不管这个接口声明中是否使用了函数式接口的注释(即@FunctionalInterface,例如上面例子的Calculate接口,没有用注解,但也是个函数式接口)。

函数式接口的疑惑
为什么Comparator接口有两个抽象方法compare和equals,Comparator还是一个函数式接口?
在这里插入图片描述
在这里插入图片描述

根据Java语言规范的定义,一个使用了该注释的接口类型声明将被视为一个函数式接口。从概念上讲,一个函数式接口有且只有一个抽象方法。由于默认方法已经有了实现,所以它们不是抽象方法。如果一个接口中声明的抽象方法是重写了超类Object类中任意一个public方法,那么这些抽象方法并不会算入接口的抽象方法数量中。因为任何接口的实现都会从其父类Object或其它地方获得这些方法的实现。

重写了超类Object类中任意一个public方法的方法并不算接口中的抽象方法!!!

所以虽然Comparator接口中有两个抽象方法compare和equals,但equals并不算入接口中的抽象方法(重写了object的equals方法),所以Comparator接口还是满足函数式接口的要求,Comparator接口是一个函数式接口。

四、Lambda 示例

线程初始化

        //1.匿名内部类方式
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Hello,World");
            }
        }).start();
        
        //2.lambda表达式方式
        new Thread(() -> {
            System.out.println("Hello,World");
        }).start();

事件处理

        Button botton=new Button();
        //1.匿名内部类方式
        botton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Hello,World");
            }
        });
        
        //2.lambda表达式方式
        Button button2=new Button();
        button2.addActionListener((e)->{
            System.out.println("Hello,World");
        });

遍历

        List list=new ArrayList();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        for(Object t:list){
            System.out.println(t);
        }
        //lambda表达式方式
        list.forEach(t-> System.out.println(t));

总结

Lambda表达式是函数式编程的体现,只有确保接口中有且仅有一个抽象方法,Lambda表达式才能顺利地推导出所实现的这个接口中的方法。以后的章节会学习到Stream接口,该接口可以将集合、数组中的元素转换为Stream流的形式,并结合Lambda表达式的优势进一步简化操作,。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
当你想要在某个地方定义一个简短的匿名函数时,可以使用C++中的lambda表达式lambda表达式是C++11引入的一种特性,它允许你在需要函数对象的地方定义一个函数,而不必显式地创建一个函数对象。 下面是一个lambda表达式的基本语法: ``` [capture](parameters) -> return_type { // 函数体 } ``` - `capture`:捕获列表,用于指定lambda表达式可以访问的外部变量。可以为空`[]`,表示不捕获任何外部变量;可以使用`[var]`来捕获一个变量;可以使用`[var1, var2]`来捕获多个变量。也可以使用`[=]`来按值捕获所有外部变量,或者使用`[&]`来按引用捕获所有外部变量。 - `parameters`:参数列表,与函数的参数列表类似。可以省略参数列表,如果不需要参数的话。 - `return_type`:返回类型,用于指定lambda表达式的返回类型。可以省略返回类型,编译器会根据函数体自动推断返回类型。 下面是一个简单的例子,演示了如何使用lambda表达式来对一个整数数组进行排序: ```cpp #include <iostream> #include <vector> #include <algorithm> int main() { std::vector<int> nums = {2, 4, 1, 3}; // 使用lambda表达式排序 std::sort(nums.begin(), nums.end(), [](int a, int b) { return a < b; }); // 输出排序后的结果 for (int num : nums) { std::cout << num << " "; } return 0; } ``` 输出结果为:1 2 3 4 在这个例子中,lambda表达式被用作`std::sort`函数的第三个参数,用于指定排序的规则。lambda表达式捕获了外部变量`a`和`b`,并根据它们的大小关系来确定排序顺序。 希望这个例子可以帮助你理解lambda表达式的使用。如果还有其他问题,请随时提问!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JinziH Never Give Up

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值