首页IT科技回炉重造图片加说说(《回炉重造》——Lambda表达式)

回炉重造图片加说说(《回炉重造》——Lambda表达式)

时间2025-07-10 04:46:28分类IT科技浏览4579
导读:前言 Lambda 表达式(Lambda Expression),相信大家对 Lambda 肯定是很熟悉的,毕竟我们数学上经常用到它,即 λ 。不过,感觉数学中的 Lambda 和编程语言中的 Lambda 表达式没啥关系,要说有关系就是都有 Lambda 这个词,噢!当然还有一个关系就是 Lambda 演算。...

前言

Lambda 表达式(Lambda Expression)              ,相信大家对 Lambda 肯定是很熟悉的                   ,毕竟我们数学上经常用到它      ,即 λ               。不过          ,感觉数学中的 Lambda 和编程语言中的 Lambda 表达式没啥关系                    ,要说有关系就是都有 Lambda 这个词         ,噢!当然还有一个关系就是 Lambda 演算                   。

λ 演算(英语:lambda calculus      ,λ-calculus)是一套从数学逻辑中发展                    ,以变量绑定和替换的规则            ,来研究函数如何抽象化定义            、函数如何被应用以及递归的形式系统      。它由数学家阿隆佐·邱奇在20世纪30年代首次发表          。lambda演算作为一种广泛用途的计算模型   ,可以清晰地定义什么是一个可计算函数                    ,而任何可计算函数都能以这种形式表达和求值               ,它能模拟单一磁带图灵机的计算过程                    。

回到编程语言这方面,其实不只是 Java 引入了这个 Lambda 表达式                 ,其他编程语言也有                  ,比如 C++                    、Javascript       、Python 等等         。当然   ,本篇文章回顾的是 Java 中的 Lambda 表达式      。

作为一个初学者              ,下面对于 Lambda 的理解肯定不够严谨                   ,甚至可能包含错误      ,望观众老爷们能在评论区指出!

为什么要学这个 Lambda 表达式?

Java 8 的新特性          ,简化代码的编写                    。 工作中会用到                    ,防止看不懂别人写的代码            。 大家都学我也学   。

什么是 Lambda 表达式?

Lambda 表达式是一个匿名函数         ,换句话说      ,你有匿名函数                    ,那么它这个函数就是所谓的 Lambda 表达式                    。

所谓匿名函数            ,顾名思义   ,就是没有函数名的函数               。

那么肯定有小伙伴会说                    ,没有函数名               ,那我怎么调用这个函数啊?

是的,这个问题问得很好                 ,先保持这个疑问!在回答这个问题之前                  ,我先来说说另一个概念——「函数式编程」。

什么是函数式编程?

函数式编程是一种编程范式   ,除此之外              ,还有声明式编程         、命令式编程                   ,也都是编程范式                 。

好吧      ,这里又扯出一个新的专业名词——「编程范式(Programming Paradigm)」                  。范式?相信正在阅读的你          ,在学习数据库知识的时候                    ,肯定学过第一范式                   、第二范式           、第三范式         ,那现在又有一个编程范式      ,这是什么鬼?

百度百科是这样说的:

编程范型      、编程范式程序设计法(英语:Programming paradigm)                    ,(即模范                  、典范之意            ,范式即模式              、方法)   ,是一类典型的编程风格                    ,是指从事软件工程的一类典型的风格(可以对照方法学)   。如:函数式编程   、程序编程                  、面向对象编程                 、指令式编程等等为不同的编程范型              。

是不是太官方了               ,没关系,简单理解                 ,我认为知道函数式编程是一种写代码时的风格就OK了                   。

我们需要注意的是                  ,函数式编程中的「函数」二字   ,是数学上的函数              ,并不是我们现在习惯理解的函数                   ,也就是说      ,这是纯纯数学概念上的函数          ,即自变量的映射                    ,比如 $y = f(x)$         ,自变量 $x$      ,通过函数 $f$ 映射成 $y$       。

函数式编程和 Lambda 表达式有什么关系?

可以说                    ,函数式编程允许使用一种表达式来表示一个函数            ,这种表达式就是 Lambda 表达式          。

在 Java 中   ,函数式编程是通过一个接口规范来实现的                    ,接口具有这种特点:

该接口有且只有一个抽象方法 该接口使用 @FunctionalInterface 注解进行标识

具有这个特点的接口称为「函数式接口」                    。

现在               ,回到最开始说的,「没有函数名                 ,那我怎么调用这个函数啊?」                  ,这就是函数式接口的用途了   ,接口中只有一个抽象方法              ,不用指定方法名称                   ,就能够用 Lambda 表达式来调用这个函数(方法)了      ,不需要知道函数名就能够实现调用         。好比想在某个房间(接口)找个人(方法)来做事          ,我这个房间只有一个人                    ,那么除了这个人         ,没有其他人可以来做事了      ,就不需要指定那谁谁谁过来帮忙                    ,而是直接喊:就决定是你了!(这个比喻可能也不是很恰当            ,当大概意思是这样哈哈哈)

函数式接口

Comparator

我们可以看看 Comparator 接口   ,它有 @FunctionalInterface 注解                    ,那么可以肯定它是一个函数式接口      。

@FunctionalInterface public interface Comparator<T> { int compare(T o1, T o2); boolean equals(Object obj); default Comparator<T> reversed() { return Collections.reverseOrder(this); } default Comparator<T> thenComparing(Comparator<? super T> other) { Objects.requireNonNull(other); return (Comparator<T> & Serializable) (c1, c2) -> { int res = compare(c1, c2); return (res != 0) ? res : other.compare(c1, c2); }; } ... }

有小伙伴应该要说了               ,这个接口这么多方法,为什么还能是函数式接口?

注意了啊                 ,我们可以看到一个好像是抽象的 equals 方法                  ,但是   ,因为 equals 是 Object 中的方法              ,这种对Object 类的方法的重新声明是会让方法变成一个具体的方法                    。所以                   ,不要误会了      ,这里的抽象方法就只有 compare 方法            。

那可能有小伙伴要说了          ,接口中还能有具体的方法?

是的                    ,没错         ,在 Java 8 中      ,接口中可以写具体的方法了   。比如上面的 reversed 和 thenComparing 方法                    ,都是具体的方法                    。

常见的函数式接口

java.lang.Runnable @FunctionalInterface public interface Runnable { public abstract void run(); } java.util.concurrent.Callable @FunctionalInterface public interface Callable<V> { V call() throws Exception; } java.lang.reflect.InvocationHandler @FunctionalInterface public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }

如何使用 Lambda 表达式?

在 Java 8 之前            ,我们使用 Collections 的需要比较器的 sort 方法   ,是这样的               。

等等                    ,忘了有比较器参数的 sort 方法了?没关系               ,代码给你贴上:

public static <T> void sort(List<T> list, Comparator<? super T> c) { list.sort(c); }

最开始的写法是这样的,由于 Comparator 是一个接口                 ,不能直接实例化                  ,所以需要一个类来实现这个接口作为真正的比较器类   ,然后将这个 Comparator 实例对象作为 sort 方法第二个参数传入              ,实现排序                   ,如下:

public class KeyComparator implements Comparator<Integer> { @Override public int compare(Integer v1, Integer v2) { return v1 - v2; } } List<Integer> keys = Arrays.asList(9, 3, 5, 10, 2); Collections.sort(keys, new KeyComparator()); System.out.println(keys); // [2, 3, 5, 9, 10]

后来      ,这种写法比较麻烦          ,于是用匿名内部类改写这种写法                    ,我们不需要自己去编写一个类来实现这个接口了         ,直接用匿名内部类。就是这种写法:

List<Integer> keys = Arrays.asList(9, 3, 5, 10, 2); Collections.sort(keys, new Comparator<Integer>() { @Override public int compare(Integer v1, Integer v2) { return v1 - v2; } }); System.out.println(keys); // [2, 3, 5, 9, 10]

现在      ,匿名内部类比起 Lambda 表达式                    ,也是麻烦            ,我们用 Lambda 进行改写:

List<Integer> keys = Arrays.asList(9, 3, 5, 10, 2); Collections.sort(keys, (Integer v1, Integer v2) -> {return v1 - v2;}); System.out.println(keys); // [2, 3, 5, 9, 10]

是吧   ,(Integer v1, Integer v2) -> {return v1 - v2;} 的写法                    ,没有函数名               ,也能进行调用                 。

实际上,这样还不是最简的                 ,最简的是这样:(v1, v2) -> v1 - v2

是不是很好奇啥时候能这样写?现在就告诉你!

基本语法

(参数类型 参数名) -> { 方法体 }

基本上                  ,这样写   ,是不会有问题的                  。下面说说何时能写得更加简单   。

为了便于阅读              ,下面的「方法」指的是函数式接口中的抽象方法

方法没有参数                   ,那么可以直接写小括号      ,然后箭头          ,再写中括号                    ,最后写方法体         ,即 () -> { 方法体 } 方法有多个参数      ,那么多个参数就用逗号分开                    ,同时参数类型是可以省略的            ,即 (v1, v2, ...) -> {方法体} 方法只有一个参数   ,那么小括号可以去掉                    ,直接写参数名               ,然后箭头,再中括号和方法体                 ,即 v -> {方法体} 方法体只有一条语句                  ,无论是否有返回值   ,都可以省略大括号、return 关键字及语句分号              。

情况一:方法无参数               、无返回值

常见的就是 Runnable 接口了                   。

@FunctionalInterface public interface Runnable { public abstract void run(); } 未使用 Lambda(使用匿名内部类): new Thread(new Runnable() { @Override void run() { System.out.println("线程开始跑了"); } }).start(); 使用 Lambda: // 写法一 new Thread(() -> { System.out.println("线程开始跑了") }).start(); // 写法二              ,一条语句                   ,那么省略大括号                    、return 关键字及语句分号 new Thread(() -> System.out.println("线程开始跑了")).start();

情况二:方法无参数      ,有返回值

例子:Callable 接口

@FunctionalInterface public interface Callable<V> { V call() throws Exception; } 未使用 Lambda(使用匿名内部类): FutureTask<String> stringFutureTask = new FutureTask<>(new Callable<String>() { @Override public String call() throws Exception { return "这里是返回值"; } }); stringFutureTask.run(); System.out.println(stringFutureTask.get()); 使用 Lambda: // 一条语句          ,省略大括号   、return 关键字及语句分号 FutureTask<String> stringFutureTask = new FutureTask<>(() -> "这里是返回值"); stringFutureTask.run(); System.out.println(stringFutureTask.get());

情况三:方法一个参数            、有返回值

我随便找了 JDK 中的一个接口                    ,如下:

@FunctionalInterface interface Recognizer { boolean recognize(int c); } 未使用 Lambda(使用匿名内部类): private final Recognizer A = new Recognizer() { @Override public boolean recognize(int c) { return c == a || c == A; } } 使用 Lambda: private final Recognizer A = (c) -> c == a || c == A; // 一个参数         ,可省略小括号 private final Recognizer A = c -> c == a || c == A;

情况四:方法多个参数                    、有返回值

直接举 Comparator 这个例子      。

未使用 Lambda(使用匿名内部类): List<Integer> keys = Arrays.asList(9, 3, 5, 10, 2); keys.sort(new Comparator()<Integer> { @Override public int compare(Integer v1, Integer v2) { return v1 - v2; } }); 使用 Lambda: List<Integer> keys = Arrays.asList(9, 3, 5, 10, 2); // 多个参数以逗号分开      ,可省略类型                    ,一条语句            ,省略大括号       、return 关键字及语句分号 keys.sort((v1, v2) -> v1 - v2); System.out.println(keys);

总结

到这里   ,相信大家对于 Lambda 表达式有了一个基本的认识          。总的来说:

必须是函数式接口才能使用 Lambda 表达式

语法:(参数类型 参数名称) ‐> { 方法体 }

若方法的参数列表: 没有参数                    ,则可直接用 () ; 有一个参数               ,可以省略 (),直接写参数; 有多个参数                 ,则()不可省略 () 内的参数类型可以省略 若方法体: 只有一条语句                  ,无论是否有返回值   ,都可以省略大括号         、return 关键字及语句分号                    。 处理逻辑过于臃肿复杂              ,还是使用具体子类改写较好                   ,保证可读性         。

最后的最后

由本人水平所限      ,难免有错误以及不足之处          , 屏幕前的靓仔靓女们 如有发现                    ,恳请指出!

最后         ,谢谢你看到这里      ,谢谢你认真对待我的努力                    ,希望这篇博客对你有所帮助!

你轻轻地点了个赞            ,那将在我的心里世界增添一颗明亮而耀眼的星!

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
网站SEO优化技巧(提升排名从入手) upper在python中代表什么(python中upper函数的用法是什么?)