Lambda表达式你会用吗? (2)

可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。

// 1. 不需要参数,返回值为 5 () -> 5 // 2. 接收一个参数(数字类型),返回其2倍的值 x -> 2 * x // 3. 接受2个参数(数字),并返回他们的差值 (x, y) -> x – y // 4. 接收2个int型整数,返回他们的和 (int x, int y) -> x + y // 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void) (String s) -> System.out.print(s) 函数接口

上面几个章节给大家介绍Lambda表达式的基本使用,那么是不是在任意地方都可以使用Lambda表达式呢?

其实Lambda表达式使用是有限制的。也许你已经想到了,能够使用Lambda的依据是必须有相应的函数接口。(函数接口,是指内部只有一个抽象方法的接口)

自定义函数接口

自定义函数接口很容易,只需要编写一个只有一个抽象方法的接口即可。

// 自定义函数接口 @FunctionalInterface public interface PersonInterface<T>{ void accept(T t); }

上面代码中的@FunctionalInterface是可选的,但加上该标注编译器会帮你检查接口是否符合函数接口规范。就像加入@Override标注会检查是否重载了函数一样。

那么根据上面的自定义函数式接口,我们就可以写出如下的Lambda表达式。

PersonInterface p = str -> System.out.println(str); Lambda和匿名内部类

经过上面几部分的介绍,相信大家对Lambda表达式已经有了初步认识,学会了如何使用。但想必大家心中始终有一个疑问,Lambda表达式似乎只是为了简化匿名内部类的写法,其他也没啥区别了。这看起来仅仅通过语法糖在编译阶段把所有的Lambda表达式替换成匿名内部类就可以了,事实真的如此吗?

public class Main { public static void main(String[] args) { new Thread(new Runnable() { @Override public void run() { System.out.println("Anonymous class"); } }).start(); } }

匿名内部类也是一个类,只不过我们不需要显示为他定义名称,但是编译器会自动为匿名内部类命名。Main编辑后的文件如下图

我们可以看到共有两个class文件,一个是Main.class,而另一个则是编辑器为我们命名的内部类。

下面我们来看一下Lambda表达式会产生几个class文件

public class Main { public static void main(String[] args) { new Thread(() -> System.out.println("Lambda")).start(); } }

image-20201217164610350

Lambda表达式通过invokedynamic指令实现,书写Lambda表达式不会产生新的类

Lambda在集合中的运用

既然Lambda表达式这么方便,那么哪些地方可以使用Lambda表达式呢?

我们先从最熟悉的Java集合框架(Java Collections Framework, JCF)开始说起。

为引入Lambda表达式,Java8新增了java.util.funcion包,里面包含常用的函数接口,这是Lambda表达式的基础,Java集合框架也新增部分接口,以便与Lambda表达式对接。

首先回顾一下Java集合框架的接口继承结构:

JCF_Collection_Interfaces

上图中绿色标注的接口类,表示在Java8中加入了新的接口方法,当然由于继承关系,他们相应的子类也都会继承这些新方法。下表详细列举了这些方法。

接口名 Java8新加入的方法
Collection   removeIf() spliterator() stream() parallelStream() forEach()  
List   replaceAll() sort()  
Map   getOrDefault() forEach() replaceAll() putIfAbsent() remove() replace() computeIfAbsent() computeIfPresent() compute() merge()  

这些新加入的方法大部分要用到java.util.function包下的接口,这意味着这些方法大部分都跟Lambda表达式相关。我们将逐一学习这些方法。

Collection中的新方法

如上所示,接口Collection和List新加入了一些方法,我们以是List的子类ArrayList为例来说明。了解Java7ArrayList实现原理,将有助于理解下文。

forEach()

该方法的签名为void forEach(Consumer<? super E> action),作用是对容器中的每个元素执行action指定的动作,其中Consumer是个函数接口,里面只有一个待实现方法void accept(T t)(后面我们会看到,这个方法叫什么根本不重要,你甚至不需要记忆它的名字)。

需求:假设有一个字符串列表,需要打印出其中所有长度大于3的字符串.

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzgwpp.html