java8新特性-lambda表达式

196 阅读4分钟

@[toc]

在这里插入图片描述

前言

java 8 一个大亮点就是引入了 lambda 表达式,使得代码开发更加简单。主要用于定义行内执行的方法类型接口,比如有一个接口你懒得去实现然后调用其方法就可以写一个 lambda 表达式

lambda 表达式到底做了什么事呢?具体的理解就是它实际上是一个接口的匿名实现类,箭头后是对接口中的抽象方法进行了实现,箭头前是抽象方法的传参

函数式接口

我们在学习 java 8 的 lambda 表达式的时候,首先必须要知道的就是函数式接口,这个词和 java 8 lambda 表达式一起出现的,二者相辅相成,lambda 表达式是函数式接口的匿名实现

函数式接口,是一种特殊的接口,与 java 8 中 lambda 表达式同时被定义,jdk 中使用 @FunctionalInterface 标在接口上方,来指明此接口是函数式接口,作为函数是接口表示其可以接收 lambda 表达式作为该类接口的匿名实现,比如Map.forEach()方法中接收的是一个 BiConsumer 函数式接口,因此其中可以写 lambda 表达式表示匿名实现这个函数式接口

一般的接口中所有方法必须都是抽象方法,对于函数式接口中不仅可以定义静态方法,还可以定义 default 修饰的方法default void这样该函数是接口就可以直接 new 并且调用此方法

基本格式

->前为参数,后为函数表达式的返回

expression 是一般的表达式,比如可以是a+b,不加括号表示实现的方法返回是a+b

statements 表达式可以是a=1但是如果写a+b会报错,加了括号表示返回的是整个括号中内容

(parameters) -> expression
(parameters) -> {statements;}

简单示例

public class JustForTest {
	@Test
    public void test() {
        A addition = (a, b) -> a + b;
        System.out.println(addition.caozuo(1, 2));
    }
    
    interface A {
        int sum(int x, int y);
    }
}

这个示例简单明了,addition 就类似于一个接口实现类然后使用A addiction = new 接口匿名的实现类()一样的效果了。这种 lambda 表达式的运用可以帮助我们少些很多代码

作用域

我们下面直接看几个小例子

样例一

在 lambda 表达式中声明的变量不可以在表达式外部使用。其实也很好理解,因为表达式中实际等价于实现了一个匿名内部类,类中方法中的变量是不可以在外部使用的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jtive22c-1592835276134)(C:\Users\石磊\AppData\Roaming\Typora\typora-user-images\1592820303720.png)]

样例二

作为类的 field 变量,在方法中的 lambda 表达式里可以引用它,并且可以做修改。直接看下面的例子中 variable 吧

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RVUW1kQU-1592835276136)(C:\Users\石磊\AppData\Roaming\Typora\typora-user-images\1592819964526.png)]

样例三

作为方法中的变量,方法中的 lambda 表达式中不可以修改此变量,在运行之前就可以检测出错误。下方红色波浪线。也就是说这时候其隐含了 final 属性

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f7EVxJGU-1592835276142)(C:\Users\石磊\AppData\Roaming\Typora\typora-user-images\1592820119347.png)]

Map.forEach()

前文也提到了,forEach() 方法中接收一个函数式接口 BiConsumer,因此这里可以使用 lambda 表达式(该函数式接口的匿名实现)

Map<String, String> map = new HashMap<>();
map.put("a", "1");
map.put("b", "2");
map.forEach((key, value) -> {
    System.out.println(key + ":" + value);
});

Stream中的 lambda

java 8 的流式处理也是一个很好新特性,它常常会伴随着 lambda 表达式一起使用,集合类调用流的stream() 方法,然后再调用 Stream 接口中的方法,这些方法中的参数很多都是接口,这样就可以做成 lambda 表达式了。

这里没有专门讲 Stream 流式处理,博主的另一篇博文:java8新特性-stream流式处理 专门有讲解

双冒号 :: 简写 lambda

双冒号::是用来简写 lambda 表达式,让其更加简洁,这种简写学名是η-conversion,读作eta-conversion。双冒号前面的为类名,后面是该类中的方法,整体表示匿名实现某个接口,接口中方法的实现使用的是该类中的方法

具体怎么理解呢?双冒号的整个表达式实际就是一个接口的匿名实现类,双冒号后是用什么已经实现的方法代替要实现的接口中的抽象方法,双冒号前指明是哪个类

举个例子,现在假如存在接口 A,我们来写个常规的 lambda 表达式

interface A {
    int sum(int a, int b);
}

public class JustForTest {
    @Test
    public void test1() {
        A a = (a, b) -> a + b;
    }
}

我们再用双冒号来实现

interface A {
    int sum(int a, int b);
}

public class JustForTest {
    @Test
    public void test1() {
        A a = Integer :: sum;
    }
}