Java 8 中的函数式接口@Functional 注解和案例

位置:首页>文章>详情   分类: Java教程 > 编程技术   阅读(125)   2024-06-13 06:21:40

函数式接口是 Java 8 最重要的概念之一,它实际上为 lambda 表达式提供支持,但许多开发人员并没有付出足够的努力来理解它,而是在没有首先了解函数式接口在 Java 8 中的作用的情况下花时间学习 lambda 表达式和 Stream API . 除非你知道什么是函数式接口以及 lambda 与它的关系,否则你无法使用 Java 8 的强大功能,例如lambda 表达式stream API。如果不了解功能接口,您将无法理解可以在代码中的哪些地方使用 lambda,而且您将难以编写方法所期望的 lambda 表达式,因此,重要的是很好地理解 Java 8 中的函数式接口。

在本文中,我将尝试通过解释什么是函数式接口、什么是 @Functional 注释、它们与 lambda 表达式的关系以及它们如何帮助您使用 lambda 表达式来填补这一空白在你的代码中。那么,让我们从第一件事开始,什么是函数式接口?

什么是 Java 8 中的函数式接口

好吧,功能接口只不过是一个只有一个抽象方法的接口,例如ComparableRunnableEventListenerComparator 等。您可以看到这些接口甚至在 JDK 8 之前就已存在于 Java 中,但为什么我们称这样的接口为函数式接口呢?

这是一个很好的问题,如果你对函数式编程有一点了解,你就会知道它允许你传递代码,即函数,就像你将数据或对象传递给方法一样。这些只有一个抽象方法的接口被用来传递代码,就像在函数式编程语言中你传递一个函数一样这就是它们被称为函数式接口的原因

例如,您可以通过实现 Comparator 接口创建匿名类来直接传递代码来比较对象,如下所示:

Collections.sort(list, new Comparator(){

public int compare(String s1, String s2){

return s1.length() - s2.length();

}

});

因此,如果仔细观察,您会发现我们正在使用这些接口将代码传递给函数。它们也被称为策略接口,因为这是策略模式的实现,其中构成策略的代码被注入到运行时运行该策略的代码中。

顺便说一句,如果您不知道什么是策略模式,那么我建议您阅读从 0 到 1:设计模式 – 24 That Matter – In Java,因为设计模式的知识对于提高效率很重要用Java编码。

所以,现在我们知道什么是函数式接口,让我们了解它们与 lambda 表达式 的关系,以及了解函数式接口对于使用一个 lambda 表达式?

嗯,最重要的是要记住,在 Java 中 lambda 表达式的唯一用途是将它们转换为函数式接口。

这意味着如果一个方法正在接受函数式接口,您可以传递 lambda 表达式,这进一步意味着,您可以将 lambda 传递给所有接受 Comparator< 的现有方法/code>、$ 或任何其他只有一个抽象方法的接口。

这就是为什么Java中的lambda表达式也被称为SAM类型的原因,其中SAM表示Single Abstract Method。

@Functional 注解有什么作用?

现在,让我们看看 @Functional 注解有什么作用?如果你只是把 @Functional 注释放在上面,它会让接口起作用吗?好吧,不,它不会那样做。事实上,它是可选的

这意味着您可以在不使用 @Functioanl 注释的情况下创建一个功能接口,就像您可以覆盖一个方法而不需要将 @Override 注释放在方法之上一样。那么, @Functional注解的真正用途是什么?

嗯,它可以确保接口实际上只有一个抽象方法,并且它还向 Javadoc 等工具提供了一个提示,表明该接口是一个功能接口。它与 @Override 注释非常相似,后者通过验证您是否实际覆盖了方法来帮助防止人为错误。

@Override 类似,其最佳实践是将 @Functional 注释放在具有单个抽象方法的方法之上,以向 Javadoc 等工具表明它们是功能接口。

所有在 java.util.function 包中添加的新功能接口都使用 @Functional 注释进行注释。

顺便说一句,是的,我们在 JDK 8 中有更多的功能接口,特别是通用功能接口,如 PredicateSupplierConsumerFunctionBiFunctionUnaryOperator 等。请参阅 Java 8:初学者基础知识 以深入了解所有这些接口。

这些功能接口允许您以 lambda 表达式的形式将代码传递给函数,并允许创建可以对这些代码进行操作的强大方法,例如 filter() 接受 Predicate 并允许您传递接受一个参数并返回布尔值的代码。

函数式接口和 Lamda 表达式有什么关系

函数式接口的知识如何影响lambda表达式的书写?好吧,除非你不了解函数式接口,否则你无法编写可以转换为该函数式接口的 lambda 表达式。

例如,merge() 接口的 java.util.Map 方法接受一个 BiFunction,但是如果你不知道什么是 BiFunction 那么你就不能为它编写 lambda。

BiFunction 是一个函数式接口,它有一个接受两个参数 T 和 U 并返回对象 R 的方法。

这意味着您可以将 lambda 传递给此方法,该方法处理两个参数并返回一个对象,例如merge(key, value, (v1, v2) -> v1 + v2) 这里的(v1, V2) -> v1 + v2是一个lambda表达式,可以转换为BiFunction函数式接口的一个实例。

一个更简单的示例是 Predicate ,它接受一个类型 T 并返回一个布尔值。如果您查看 Stream 类的 filter() 方法,它接受一个 Predicate:

filter(Predicate predicate)

这意味着您可以传递任何接受一个参数的 lambda 表达式并将布尔值返回给此方法,例如age -> age > 15 or s -> s.length == 15,两者都可以,但如果你不知道什么是 Predicate 接口,你就做不到。

函数式接口的另一个示例是 Consumer ,它接受类型 T 的参数并且不返回任何内容。 JDK 8中Iterable的forEach()方法很好地利用了这一点,如下所示:

forEach(Consumer action)

您可以看到 forEach() 接受一个 Consumer,这意味着您可以将一个 lambda 表达式传递给它,该表达式只有一个参数并且不返回任何内容或返回 void,例如

s -> System.out.println(s)

代码 System.out.println() 不返回任何内容,它只是在控制台中打印一行。

你可以看到,如果你知道函数式接口,那么你可以轻松地编写一个 lambda 表达式来传递,因此必须具备良好的函数式接口知识。我建议您通读 java.util.function 包中的所有功能接口并理解它们。

我将在接下来的文章中解释 java.util.function 包中一些更复杂的功能接口,但如果你等不及了,我建议你学习一下这个 Java 9 Master Class 学习更多关于 lambdas 和其他 Java 8 概念的课程。

这就是关于什么是 Java 中的函数式接口。您还了解了 @Functional 注释的作用是什么,以及为什么需要充分了解功能接口才能在 Java 8 的代码中有效使用 lambda 表达式。如果您还没有开始使用 Java 8,我建议你现在就做,因为在未来的几年里,每个人都将使用 Java 8 进行编码,如果你不了解 lambda 表达式和 Java 8 中引入的新特性,那么你将被甩在后面。

供进一步学习的其他Java 8 教程和资源

Java 8 的新特性:Lambdas

如何使用 lambdas 按键和值对 HashMay 进行排序?

如何在 Java 8 中使用 map 和 flatMap?

如何在 Java 8 中进行 Map Reduce?

如何在 Java 8 中将 lambda 表达式转换为方法引用?

Java SE 8 新特性 – 完整指南

感谢您到目前为止阅读本文。如果您喜欢我对 Functional 接口和 @Functional 注释的解释,请与您的朋友和同事分享。如果您有任何问题或反馈,请发表评论。

标签2: Java教程
地址:https://www.cundage.com/article/jcg-functional-interface-java-8-functional-annotation-examples.html

相关阅读

Java HashSet 教程展示了如何使用 Java HashSet 集合。 Java哈希集 HashSet 是一个不包含重复元素的集合。此类为基本操作(添加、删除、包含和大小)提供恒定时间性...
SpringApplicationBuilder 教程展示了如何使用 SpringApplicationBuilder 创建一个简单的 Spring Boot 应用程序。 春天 是用于创建企业应...
通道是继 buffers 之后 java.nio 的第二个主要新增内容,我们在之前的教程中已经详细了解了这一点。通道提供与 I/O 服务的直接连接。 通道是一种在字节缓冲区和通道另一端的实体(通...
课程大纲 Elasticsearch 是一个基于 Lucene 的搜索引擎。它提供了一个分布式的、支持多租户的全文搜索引擎,带有 HTTP Web 界面和无模式的 JSON 文档。 Elasti...
解析器是强大的工具,使用 ANTLR 可以编写可用于多种不同语言的各种解析器。 在这个完整的教程中,我们将: 解释基础:什么是解析器,它可以用来做什么 查看如何设置 ANTLR 以便在 Java...
Java 是用于开发各种桌面应用程序、Web 应用程序和移动应用程序的最流行的编程语言之一。以下文章将帮助您快速熟悉 Java 语言,并迈向 API 和云开发等更复杂的概念。 1. Java语言...
Java中的继承是指子类继承或获取父类的所有非私有属性和行为的能力。继承是面向对象编程的四大支柱之一,用于提高层次结构中类之间的代码可重用性。 在本教程中,我们将了解 Java 支持的继承类型,...
Java Message Service 是一种支持正式通信的 API,称为 网络上计算机之间的消息传递。 JMS 为支持 Java 程序的标准消息协议和消息服务提供了一个通用接口。 JMS 提...
之前,我介绍了spring 3 + hibernate 集成 示例和struts 2 hello world 示例。在本教程中,我将讨论在将 spring 框架与 struts 与 hibern...
Java 项目中的一项常见任务是将日期格式化或解析为字符串,反之亦然。解析日期意味着你有一个代表日期的字符串,例如“2017-08-3”,你想把它转换成一个代表 Java 中日期的对象,例如Ja...