Java 8 函数式编程(一)(概念介绍)

382 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情

从这篇文章我们开始介绍Java 8 函数式编程的一些知识。Java 8 的函数式编程如果之前没有了解过,那么本篇文章将会起到很好的入门效果。

Java 8 函数式接口理解及语法

函数式编程的最浅显易懂且直白的理解就是可以使用一个函数作为某个方法的参数。

我们都知道,Java 8 相比于前几个版本,最大的改动之一就是引入了函数式编程的概念。

引入了一个新的概念,肯定会对应着新的语法。而Java8 中函数式编程语法可以精简Java 代码。

可能光看文字比较难理解,这里使用函数式接口Consumer 举例,接口中有一个抽象方法accept,这个方法特点是只有输入而没有输出。

使用我们既有的Java 语言思维,如果要定义一个Consumer对象,一般就会这么写:

Consumer c = new Consumer() {
    @Override
    public void accept(Object o) {
        System.out.println(o);
    }
};

但是到了Java 8 中,针对函数式编程接口,定义就可以变成这样:

(代码中使用了lambda 表达式,后续会介绍)

Consumer c = (o) -> {
    System.out.println(o);
};  

代码分析

其实函数式编程接口都有且只有一个抽象方法,使用这种写法时,编译器会将这段代码编译后,当作该抽象方法的实现。

所以说,如果接口有多个抽象方法,编译器就不知道这段函数应该是实现哪个方法的了。

函数实现:

通过上述描述,我们可不难理解,等号=后面的函数体代码,我们就可以看成是accept抽象函数的实现。

输入:

对应这个函数的输入就是-> 前面的部分,即被()包围的部分。例子中只有一个输入参数,但是实际上输入是可以有多个的,比如说有两个参数时的写法:(a, b)

当然也可以没有输入,此时直接就可以是()

函数体:

函数体就是对应->后面的部分,也就是被{}包围的部分。可以是一个语句,可以是一段代码。

输出:

对于函数式编程,可以没有返回值,也可以有返回值。

有返回值的时候,代码段的最后一句需要使用return返回对应的值;同时,如果当函数体中只有一个语句,此时就可以去掉外面的大括号,可以进一步简化为:

Consumer c = (o) -> System.out.println(o);

但是这样也还不是最简的,因为这里只是简单地实现“输出”的功能,调用了System.out中的println静态方法对输入参数直接进行输出,我们观察到,这里就是accept 方法的输入参数是什么,传入System.out.println 中的参数就是什么,所以我们可以进一步简化成以下写法:

Consumer c = System.out::println;

这段代码表示的意思就是针对输入的参数,将会调用System.out中的静态方法println将其输出。

总结

从最开始的传统Java 写法到最后的函数式编程写法我们可以看出,使用函数式编程,可以精简很多代码,但是这也需要对此语法有充分的了解。

其实通过最后一段代码:Consumer c = System.out::println;,我们可以对函数式编程有进一步的理解:这个Consumer接口直接就可以当成一个函数,此函数接收一个输入参数(其实这些都已经在代码中省略了),然后针对这个输入参数进行处理(后面的System...相关代码)。

其实它的本质仍旧是一个对象,但我们如果使用之前的写法会发现,有很多可以被当做“格式”类的代码会被加进去;而函数式编程已经省去了这些代码,比如说对象定义过程。

这种我们可以直接使用一段代码来给函数式接口对象赋值。(也就是生成一个函数式接口对象)

但是透过现象看本质,这个函数式对象因为仍旧是一个对象,因此可以做为其它方法的参数或者返回值,可以与其他代码,不论是老版本还是Java 8,实现无缝集成!

但是透过现象看本质,这个函数式对象因为仍旧是一个对象,因此可以做为其它方法的参数或者返回值,可以与其他代码,不论是老版本还是Java 8,实现无缝集成!

但是透过现象看本质,这个函数式对象因为仍旧是一个对象,因此可以做为其它方法的参数或者返回值,可以与其他代码,不论是老版本还是Java 8,实现无缝集成!

之后我们会对Java 中的几个预先定义的函数式接口进行分析。