下载贤集网APP入驻自媒体
了解如何创建自定义函数接口,以及为什么应该尽量使用内置的接口。概览lambda 表达式的类型是什么?一些语言使用函数值或函数对象来表示 lambda 表达式,但是 Java 语言没有这么做。Java 使用函数接口来表示 lambda 表达式类型。这其实是一种确保 Java 语言旧版本的向后兼容性的有效途径。
看下面一段代码:这是一个线程复制代码这里 Thread 类的构造函数想要一个实现 Runnable 的实例。在本例中我们传递了一个 lambda 表达式,而不是一个对象。实际上我们可以向各种各样的方法和构造函数传递 lambda 表达式,包括在 Java8 之前创建的方法和构造函数。这很有效,因为 lambda 表达式在 Java 中表示为函数接口。
函数接口有三条重要法则:一个函数接口只有一个抽象方法。 在 Object 类中属于公共方法的抽象方法不会被视为单一抽象方法。 函数接口可以有默认方法和静态方法。任何满足单一抽象方法法则的接口,都会被自动视为函数接口。这包括 Runnable 和 Callable 等传统的接口,以及您自己构建的自定义接口。内置函数接口除了已经提到的单一抽象方法之外,JDK 8 还包含多个新函数接口。最常用的接口包括 Function、Predicate 和 Consumer,它们是在 java.util.function 包中定义的。Stream 的 map 方法接受 Function 作为参数。类似地,filter 使用 Predicate,forEach 使用Consumer。该包还有其他函数接口,比如 Supplier、BiConsumer 和 BiFunction。
可以将内置函数接口用作我们自己的方法的参数。例如,假设我们有一个 Device 类,它包含方法 checkout 和 checkin 来指示是否正在使用某个设备。当用户请求一个新设备时,方法 getFromAvailable 从可用设备池中返回一个设备,或在必要时创建一个新设备。
我们可以实现一个函数来借用设备:id: 2 price: 983id: 1 price: 1225id: 3 price: 1554复制代码我们传递一个匿名内部类作为 transformAndPrint 方法的参数。在 transform 方法内,调用给定流的 sorted 方法,这会对订单项进行排序。
lambda表达式的强大功能
在任何需要函数接口的地方,我们都有三种选择:传递一个匿名内部类。 传递一个 lambda 表达式。 在某些情况下传递一个方法引用而不是 lambda 表达式。order.transformAndPrint(input -> input.sorted(Comparator.comparing(OrderItem::getPrice)));[/code]
与我们最初提供的匿名内部类相比,这简洁得多且更容易阅读。
自定义函数接口与内置函数接口
我们上边演示了自定义函数接口,那么自定义函数接口有什么优势和不足呢?
首先优势:
您可以为自定义接口提供一个描述性名称,帮助其他开发人员修改或重用它。
只要您高兴,可以为抽象方法提供任何具有有效语法的名称。只有接口的接收者会获得此优势,而且仅在传递抽象方法时才会体现出来。传递 lambda 表达式或方法引用的调用不会获得此优势。
您可以在自己的接口中使用参数化的类型,或者让它保持简单并特定于某些类型。
您可以编写自定义的默认方法和静态方法,它们可供该接口的其他实现使用。
自定义接口的不足:
想创建多个接口,所有接口都具有相同签名的抽象方法,比如接受 String 作为参数并返回 Integer。尽管方法的名称可能有所不同,但它们大部分都是多余的,可替换为一个具有通用名称的接口。
任何想要使用自定义接口的人,都必须投入额外的精力来学习、理解和记住它们。
那种接口最好
了解了自定义函数接口与内置函数接口的优缺点之后,那么我们该如何采用那种接口呢?我们回顾一下 Transformer 接口。
public void transformAndPrint(Transformer> transformOrderItems) {[/code]
方法 transformAndPrint 接收一个负责执行转换的参数。该转换可能对 orderItems 集合中的元素进行重新排序。或者,它可能屏蔽每个订单项的部分袭击。或者什么也不做。我们将具体的实现留给调用者。
重要的是,调用方知道它们可以将转换实现作为参数提供给 transformAndPrint 方法。函数接口的名称和它的文档应该提供这些细节。在本例中,从参数名称 (transformOrderItems) 也可以清楚了解这些细节,而且它们应包含在 transformAndPrint 函数的文档中。尽管函数接口的名称很有用,但它不是了解函数接口用途和用法的唯一途径。
仔细查看 Transformer 接口,并将它的用途与 JDK 的内置函数接口进行比较,我们看到 Function 可以取代 Transformer。
public void transformAndPrint(Function, Stream> transformOrderItems) {
transformOrderItems.apply(items.stream())
.forEach(System.out::println);
}[/code]
对 transformAndPrint 的调用使用了一个匿名内部类,我们还需要更改这一点。但是,我们已更改该调用来使用 lambda 表达式:
order.transformAndPrint(orderItems -> orderItems.sorted(comparing(OrderItem::getPrice)));[/code]
我们看到我们同样可以用方法引用或者 lambda 表达式去调用,函数接口的名称与 lambda 表达式无关,它仅与编译器有关,编译器将 lambda 表达式参数与方法参数联系起来。方法名称是 transform 还是 apply 同样与调用方无关。
使用内置的函数接口让我们的接口减少了一个,调用该方法也具有同样功效。我们也没有损害代码的可读性。
总结
将 lambda 表达式设计为函数接口类型的设计策略,有助于 Java 向早期的版本进行兼容。可以将 lambda 表达式传递给任何通常接收单一抽象方法接口的旧函数。要接收 lambda 表达式,方法的参数类型应为函数接口。
在某些情况下,创建自己的函数接口是合情合理的,但在这么做时应该小心谨慎。仅在应用程序需要高度专业化的方法时,或者现有接口无法满足您的需求时,才考虑自定义函数接口。请始终检查一个 JDK 的内置函数接口中是否存在该功能。尽量使用内置函数接口。
上一篇:java安装环境配置注意的地方
下一篇:三分钟学会用SpringMVC搭建最小系统(超详细)回复举报