栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java如何支持函数式编程?

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java如何支持函数式编程?

.map(s -> s.length()) // map返回Stream对象

.filter(l -> l <= 3) // filter返回Stream对象

.max((o1, o2) -> o1-o2); // max终止操作:返回Optional

System.out.println(result.get()); // 输出2

}

}

Lambda表达式

前面提到Java引入Lambda表达式的主要作用是简化代码编写。实际上,我们也可以不用Lambda表达式来书写例子中的代码。我们拿其中的map函数来举例说明。

下面三段代码,第一段代码展示了map函数的定义,实际上,map函数接收的参数是一个Function接口,也就是函数接口。第二段代码展示了map函数的使用方式。第三段代码是针对第二段代码用Lambda表达式简化之后的写法。实际上,Lambda表达式在Java中只是一个语法糖而已,底层是基于函数接口来实现的,也就是第二段代码展示的写法。

// Stream类中map函数的定义:

public interface Stream extends BaseStream {

 Stream map(Function mapper);

//…省略其他函数…

}

// Stream类中map的使用方法示例:

Stream.of(“fo”, “bar”, “hello”).map(new Function() {

@Override

public Integer apply(String s) {

return s.length();

}

});

// 用Lambda表达式简化后的写法:

Stream.of(“fo”, “bar”, “hello”).map(s -> s.le 《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 ngth());

Lambda表达式包括三部分:输入、函数体、输出。表示出来的话就是下面这个样子:

(a, b) -> { 语句1;语句2;…; return 输出; } //a,b是输入参数

实际上,Lambda表达式的写法非常灵活。上面给出的是标准写法,还有很多简化写法。比如,如果输入参数只有一个,可以省略 (),直接写成 a->{…};如果没有入参,可以直接将输入和箭头都省略掉,只保留函数体;如果函数体只有一个语句,那可以将{}省略掉;如果函数没有返回值,return语句就可以不用写了。

Optional result = Stream.of(“f”, “ba”, “hello”)

.map(s -> s.length())

.filter(l -> l <= 3)

.max((o1, o2) -> o1-o2);

// 还原为函数接口的实现方式

Optional result2 = Stream.of(“fo”, “bar”, “hello”)

.map(new Function() {

@Override

public Integer apply(String s) {

return s.length();

}

})

.filter(new Predicate() {

@Override

public boolean test(Integer l) {

return l <= 3;

}

})

.max(new Comparator() {

@Override

public int compare(Integer o1, Integer o2) {

return o1 - o2;

}

});

Lambda表达式与匿名类的异同集中体现在以下三点上:

  • Lambda就是为了优化匿名内部类而生,Lambda要比匿名类简洁的多得多。

  • Lambda仅适用于函数式接口,匿名类不受限。

  • 即匿名类中的this是“匿名类对象”本身;Lambda表达式中的this是指“调用Lambda表达式的对象”。

函数接口

实际上,上面一段代码中的Function、Predicate、Comparator都是函数接口。我们知道,C语言支持函数指针,它可以把函数直接当变量来使用。

但是,Java没有函数指针这样的语法。所以它通过函数接口,将函数包裹在接口中,当作变量来使用。实际上,函数接口就是接口。不过,它也有自己特别的地方,那就是要求只包含一个未实现的方法。因为只有这样,Lambda表达式才能明确知道匹配的是哪个方法。如果有两个未实现的方法,并且接口入参、返回值都一样,那Java在翻译Lambda表达式的时候,就不知道表达式对应哪个方法了。

函数式接口也是Java interface的一种,但还需要满足:

  • 一个函数式接口只有一个抽象方法(single abstract method);

  • Object类中的public abstract method不会被视为单一的抽象方法;

  • 函数式接口可以有默认方法和静态方法;

  • 函数式接口可以用@FunctionalInterface注解进行修饰。

满足这些条件的interface,就可以被视为函数式接口。例如Java 8中的Comparator接口:

@FunctionalInterface

public interface Comparator {

int compare(T o1, T o2);

boolean equals(Object obj);

default Comparator reversed() {

return Collections.reverseOrder(this);

}

public static > Comparator reverseOrder() {

return Collections.reverseOrder();

}

//省略…

}

函数式接口有什么用呢?一句话,函数式接口带给我们最大的好处就是:可以使用极简的lambda表达式实例化接口。为什么这么说呢?我们或多或少使用过一些只有一个抽象方法的接口,比如Runnable、ActionListener、Comparator等等,比如我们要用Comparator实现排序算法,我们的处理方式通常无外乎两种:

  • 规规矩矩的写一个实现了Comparator接口的Java类去封装排序逻辑。若业务需要多种排序方式,那就得写多个类提供多种实现,而这些实现往往只需使用一次。

  • 另外一种聪明一些的做法无外乎就是在需要的地方搞个匿名内部类,比如:

public class Test {

public static void main(String args[]) {

List persons = new ArrayList();

Collections.sort(persons, new Comparator(){

@Override

public int compare(Person o1, Person o2) {

return Integer.compareTo(o1.getAge(), o2.getAge());

}

});

}

}

匿名内部类实现的代码量没有多到哪里去,结构也还算清晰。Comparator接口在Jdk 1.8的实现增加了FunctionalInterface注解,代表Comparator是一个函数式接口,使用者可放心的通过lambda表达式来实例化。那我们来看看使用lambda表达式来快速new一个自定义比较器所需要编写的代码:

Comparator comparator = (p1, p2) -> Integer.compareTo(p1.getAge(), p2.getAge());

-> 前面的 () 是Comparator接口中compare方法的参数列表,-> 后面则是compare方法的方法体。

下面将Java提供的Function、Predicate这两个函数接口的源码,摘抄如下:

@FunctionalInterface

public interface Function {

R apply(T t);  // 只有这一个未实现的方法

default  Function compose(Function before) {

Objects.requireNonNull(before);

return (V v) -> apply(before.apply(v));

}

default  Function andThen(Function after) {

Objects.requireNonNull(after);

return (T t) -> after.apply(apply(t));

}

static  Function identity() {

return t -> t;

}

}

@FunctionalInterface

public interface Predicate {

boolean test(T t); // 只有这一个未实现的方法

default Predicate and(Predicate other) {

Objects.requireNonNull(other);

return (t) -> test(t) && other.test(t);

}

default Predicate negate() {

return (t) -> !test(t);

}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/848130.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号