取法其上,得乎其中

Java 函数式接口与Stream流

概述

在之前学习过 lambda表达式,其中在创建一个线程的时候使用了如下语法。

        new Thread(() -> {
            //代码块
        }).start();

这样就成功了创建了一个线程,可在但是并没有因此而深入了解为什么要这样写,lambda表达式的具体用法到底是什么。今天便学习到了。

首先为了回答以上的问题需要先从函数式接口来入手。

函数式接口

简单的来说,函数式接口就是只包含一个抽象方法的接口,但一般会拥有多个默认方法。那么为什么要设计函数式接口呢,其实主要目的是将方法当做参数进行传递。

为了实现这样一个目的,所以在Java8中设计了lambda。

创建

一般的,我们创建一个函数式接口都要添加 @FunctionalInterface 注解。当然不加也没事,不过为了规范最好添加。

@FunctionalInterface
public interface Person {
    void play(String msg);
}

实现

以前我们在集成一个接口的时候一般都是重新创建一个类,使用 implements关键字 来实现这个接口。而当我们这次采用lambda则不需要。

    Person person = (msg) -> {
        System.out.println(msg);
    };
    person.play("111");

当我们声明这个参数类型为 "Person" 的时候,就已经代表我们后续的lambda其实就是去实现这个类,而括号中代表的是对应的参数。花括号内代表具体代码。

值得记录的是,有时可以省略以下部分代码:

  • 代码只有一句的时候可以省略花括号
  • 代码只有一句的时候如果有返回值可以省略return

所以前面那句代码可以省略为:

    Person person = () -> System.out.println(233);

写到这里应该已经发现了,我们已经成功的将这样一个接口实现为一个变量了,那么我们再回到看一眼 Thread 的代码。

    public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }

可以看到它其实是需要一个 Runnable 类型的参数,那么是不是代表这个参数类型其实也就是一个函数式接口呢?

    @FunctionalInterface
    public interface Runnable {

很明显,它也是这样的接口。自此,就解决了之前的疑问。

Stream流

为什么这篇博文要将这两者放在一起呢?其实是因为在Stream之中大量的用的了函数式接口来对一组元素进行操作。

使用

以下代码便可以获得一个 Stream 。

    List<Integer> list = Arrays.asList(50, 120, 1, 74, 10, 5, 6);
    Stream<Integer> stream = list.stream();

操作总的来说分为两种,中间操作和终止操作。简单的来说,中间操作就是对这组数据进行修改、删除...等等。而终止操作则是获得值、规约值..等等。

说到这里应该就理解了吧,其实Stream就是通过它实现了很多方便的功能,让我们可以少写很多冗余代码。

首先我们尝试使用 foreach 来进行遍历这个list,可以看到参数类型为 Consumer,就是消费者的意思,它就是一个函数式接口,而在该接口下拥有一个名为 accept 的抽象方法,并且拥有一个泛型参数,寓意为消费这个值。

所以,我们直接直接使用前面所学的实现接口方法。

        list.stream()
            .forEach((item) -> {
                System.out.println(item);
            });

这样,我们就可以成功将其遍历出来。

并行流

很明显,我们前面使用的方式简单的来说就是按照一定顺序来进行处理,也就是顺序流。但当我们拥有大量数据处理的时候速度必然会很慢,所以Java在它的基础上还添加了并行流。

其实就是加入了多线程概念。使用以下方法就可以获得并行流。

list.parallelStream()

当我们重新使用这样的方法执行 foreach 的时候,顺序并非前者那样,所以确信其本质就是多线程的流~

其他

其他用法都大同小异,除了消费者接口以外Java还集成了:

  • Function 转换,将一个或多个值处理成某个结果
  • Predicate 断言,判断当前值是否成立
  • Comparator 排序,顾名思义,在之前的排序博文中就有用到这个接口。
  • ...
Java 函数式接口与Stream流

https://ku-m.cn/index.php/archives/453/

作者

KuM

发布时间

2020-11-11

许可协议

CC BY 4.0

本页的评论功能已关闭