1. 首页
  2. 后端

java8函数式编程读书笔记————lambda表达式篇

  java8函数式编程读书笔记————lambda表达式篇

============================

在学习lambda表达式之前,我觉得有必要搞清楚两个概念。

1.什么是函数?

这里函数的概念与我们从小到大学习的数学函数没有区别即f(x)=y;

即对一个值行处理,将其映射成另一个值。

2.什么是函数式编程?

函数式编程自然和函数脱不开干系,可是函数和java语言有什么关系呢?

抛开刻板印象不谈,从概念上讲对一个值进行处理,将其映射成另一个值是不是很像接口。

比如int add(int x,int y);这算不算一个简单的函数定义。将x,y映射成它们的合。

所以在java中,函数式对象通常是指实现了特定接口的对象。而且函数式对象是被允许作为参数传递的。

为什么要引入lambda表达式

在lambda表达式之前,我们要将一个函数作为参数传递,采取的方式是匿名内部类
例1

    button.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent event) {
            System.out.println("button clicked");
        }
    });

尽管这样做为我们省去了单独定义一个接口实现类,然后再创建一个该类的对象作为参数传递的步骤。

但是这样做有个很大的缺陷,那就是我们真正要做的事只有一个那就是吧(ActionEvent event)映射成System.out.println(“button clicked”);

即(ActionEvent event)->System.out.println(“button clicked”);

作为一个致力于让代码简洁,优雅,可读性强的攻城狮,这样写无疑是违反原则的。

首先,它为了传递一行关键代码,而不得不写四行模板代码,其次这样层层套娃的编写,也让后来者看你代码时感觉很烦,认为你这个人很不专业。

lambda表达式的出现很大程度上解决了这些问题,它没有让我们的代码功能变得更加强大,但却可以使我们的代码更加优雅。

lambda表达式的概念以及特性

前文已经提到,lambda表达式是为了更优雅的进行函数式编程而引入的。
那什么是lambda表达式,它都有哪些特性呢?

lambda表达式是一种特殊的匿名函数。

作为匿名函数他必然有着匿名性和传递性这两个特征。
即lambda表达式不需要显示的定义名称并且可以作为方法参数传递。

区别于普通的匿名函数,lambda表达式的特殊就在于它的第三个特性——简洁性。

我们定义一个函数f(x)->y,省略掉它的名称(x)->y,这像不像是一个lambda表达式。

可是这样有一个问题,我们把函数名称类比为接口名称。匿名后,我怎么指定调用的是哪个方法呢?

普通的匿名内部类采用的方式就像例1,虽然省略了引用名称,但是还是需要指定抽象类和抽象类中的抽象方法

这样写出的代码就很冗余。毕竟我们想要传递的只有一句关键代码。

使用lambda表达式写出来的是这样的button.addActionListener(event -> System.out.println(“button clicked”));对比一下,尽显优雅。

lambda表达式是如何实现这种优雅的呢?

之所以说lambda优雅是因为,lambda表达式将创建匿名内部类省略到只需要指定参数和映射参数的代码。
要实现这个,首先要面临的问题就是,如何得知我要调用哪个接口?

要解决这个问题,我们要先回忆起一个概念————只有函数式接口才可以使用lambda表达式。函数式接口也就是只包含一个抽象方法的接口。

我们将lambda表达式作为参数传递到方法体中,该方法必然已经定义好了参数类型,据此编译器可以得出应该创建哪个接口的匿名内部类,因为函数式接口只有一个抽象方法接口,所以可以直接判断出改代码实现了哪个抽象方法。

lambda表达式如何选取接口,从上面已经解答,另一个关键的问题就是lambda表达式也是可以省略参数类型的,因为编译的时候程序会进行自动进行类型判断,那么它是如何进行类型推断的呢?

相信学习过python的朋友都不会感到奇怪,但在java里这还真是个新特性。如何实现这个功能也不难理解,既然我根据方法所需参数判断出要传递接口的实现类对象,又因为函数式接口只有一个抽象方法所以我也能够得知要实现哪个方法。那么根据这个方法的方法签名,我自然也能得知这个方法需要传递的参数类型。

lambda表达式也被称为闭包。

这是因为lambda表达式可以捕获其定义时所在的上下文的变量值。也就是lambda表达式在使用外部变量时是值传递。

那这就会造成一个困扰,运行过程中,如果外部的值在执行lambda表达式之前被改变了,程序执行结果就可能出错。

在lambda表达式之前,匿名内部类只允许引用被final修饰的变量。
而在java8之后,如果这个变量只被赋值过一次,也可以通过编译。

所以大家在写代码的时候有时会出现lambda表达式中引用一个集合被编译器标红的情况,不要奇怪看看这个集合有没有在被引用多次赋值。

原文链接: https://juejin.cn/post/7377664582730711059

文章收集整理于网络,请勿商用,仅供个人学习使用,如有侵权,请联系作者删除,如若转载,请注明出处:http://www.cxyroad.com/17779.html

QR code