1.3 函数式接口

1.3 函数式接口

正如我们讨论所述,在Java 中有许多已有的接口都需要封装代码块,例如Runnable或者Comparator。lambda 表达式与这些接口是向后兼容的。

对于只包含一个抽象方法的接口,你可以通过lambda 表达式来创建该接口的对象。这种接口被称为函数式接口。

注意:你可能奇怪为什么函数式接口必须只有一个抽象方法。难道接口中的方法不都是抽象的吗?事实上,接口经常会重新声明Object 类中的方法,例如toString 或者clone,而这些方法声明并不是抽象的。(Java API 中的某些接口重新声明Object 类的方法,是为了关联javadoc 的注释。具体例子可以参考Comparator API。)你将在第1.7 节看到更重要的一点,即在Java 8 中接口可以声明非抽象的方法。

为了演示函数式接口转换,我们以Arrays.sort 方法为例。该方法的第二个参数需要一个Comparator 接口(该接口只含有一个方法)的实例。接下来我们编写一个简单的lambda 表达式:

  1. Arrays.sort(words,
  2. (first, second) -> Integer.compare(first.length(), second.length()));

在这个表达式背后,Arrays.sort 方法会接收一个实现了Comparator<String>接口的类的实例。调用该对象的compare 方法会执行lambda 表达式中的代码。这些对象和类的管理完全依赖于如何实现,因此比传统的内部类效率更高。你最好将一个lambda 表达式想象成一个函数,而不是一个对象,并记住它可以被转换为一个函数式接口。

这种到接口的转换使得lambda 表达式非常引人注目,它的语法是如此精简。下面是另外一个示例:

  1. button.setOnAction(event ->
  2. System.out.println("Thanks for clicking!"));

显然其可读性也比内部类好了很多。

事实上,函数式接口的转换是你在Java 中使用lambda 表达式能做的唯一一件事。在其他支持函数文本的编程语言中,你可以声明像(String, String) -> int 这样的函数类型,声明这种类型的变量,并使用这些变量来保存函数表达式。但是,Java 设计者们还是决定坚持使用熟悉的接口概念,而没有将函数类型添加到Java 中。

注意:你甚至不能将一个lambda 表达式赋值给一个Object 类型的变量,因为Object 不是一个函数式接口。

Java API 在java.util.function 包中定义了许多非常通用的函数式接口(我们将在第2 章和第3 章中对这些接口进行详细讲解)。其中接口BiFunction<T,U,R> 描述了T 和U 类型的方法参数及返回类型R。你可以将我们的字符串比较lambda 表达式保存在一个该类型的变量中。

  1. BiFunction<String, String, Integer> comp
  2. = (first, second) -> Integer.compare(first.length(), second.length());

但是,这对排序并不能起到什么帮助作用。不存在接收BiFunction 作为参数的Arrays.sort 方法。如果你之前使用过其他函数式编程语言,你可能会对此感到奇怪。

但是对于Java 开发人员来说,这再自然不过了。像Comparator 这样的接口有着特定的目的,而不仅仅是一个接收参数和返回类型的方法。Java 8 保留了这一习惯。当你希望使用lambda 表达式时,你仍然要牢记表达式的目的,并为它指定一个函数式接口。

现在Java 8 本身的API 使用了java.util.function 中的接口,将来这些接口很可能被应用在各个地方。但是请记住,任何一个lambda 表达式都可以等价转换成现在所使用的API 中对应的函数式接口。

注意:你可以在任意函数式接口上标注@FunctionalInterface 注解,这样做有两个好处。首先,编译器会检查标注该注解的实体,检查它是否是只包含一个抽象方法的接口。另外,在javadoc 页面也会包含一条声明,说明这个接口是一个函数式接口。

该注解并不要求强制使用。从概念上来讲,所有只含有一个抽象方法的接口都是函数式接口,但是使用@FunctionalInterface 注解会让你的代码看上去更清楚。

最后,当一个lambda 表达式被转换为一个函数式接口的实例时,请注意处理检查期异常。如果lambda 表达式中可能会抛出一个检查期异常,那么该异常需要在目标接口的抽象方法中进行声明。例如,以下表达式会产生一个错误:

  1. Runnable sleeper = () -> { System.out.println("Zzz"); Thread.sleep(1000); };
  2. //错误:Thread.sleep 可以抛出一个检查期的InterruptedException。

由于Runnable.run 不能抛出任何异常,所以这个赋值是不合法的,有两种方法可以修正该问题。一种是在lambda 表达式中捕获异常,另一种是将lambda 表达式赋给一个其抽象方法可以抛出异常的接口。例如,Callable 接口的call 方法可以抛出任何异常,因此,你可以将该lambda 表达式赋给Callable<Void>(如果你添加一条“return null”语句)。

时间: 2024-10-14 03:13:17

1.3 函数式接口的相关文章

函数式接口

函数式接口定义 1.如果一个接口只有一个抽象方法,那么该接口就是一个函数式接口 2.如果我们在某接口上声明了FunctionalInterface注解,那么编译器就会按照函数式接口的定义来约束该接口 3.如果某个接口只有一个抽象方法,但我们并没有给该接口声明FunctionalInterface注解,那么编译器依旧会将该接口看作是函数式接口 4.函数式接口的实例可以通过lambda表达式.方法引用.构造方法引用来创建 5.如果一个接口声明了一个抽象方法,该抽象方法重写了Object中的某个方法,

Java8学习笔记(二)-函数式接口与方法引用

一.Lambada表达式到底是什么 首先先看一下下面的一段代码! package cn.org.kingdom.jdk8; @FunctionalInterface interface MyInterface { void test(); String toString(); } public class Test { public void test(MyInterface inter) { System.out.println("*************************"

Java8 新特性----函数式接口,以及和Lambda表达式的关系

这里来讲解一下Java8 新特性中的函数式接口, 以及和Lambda 表达式的关系.看到过很多不少介绍Java8特性的文章,都会介绍到函数式接口和lambda表达式,但是都是分别介绍,没有将两者的关系说明清楚,在这里,把自己的理解整理如下: 一.函数式接口: 函数式接口其实本质上还是一个接口,但是它是一种特殊的接口:SAM类型的接口(Single Abstract Method).定义了这种类型的接口,使得以其为参数的方法,可以在调用时,使用一个lambda表达式作为参数.从另一个方面说,一旦我

【Java系列教程】一起爪哇Java 8(一)——函数式接口

引言 目前由于系统已经全面切换为JDK8,所以有必要系统的了解一下Java8的一些新特性,以便后续在日常工作中可以使用一些高级特性来提高编程效率. 因为Java8引入了函数式接口,在java.util.function包含了几大类函数式接口声明.这里第一篇主要研究一下Function相关的接口. FunctionalInterface注解 Java8的新引入,包含函数式的设计,接口都有@FunctionalInterface的注解.就像这个注解的注释说明一样,它注解在接口层面,且注解的接口要有且

java8简单入门--函数式接口 @FunctionalInterface

1.介绍 看了几篇关于 java8 入门的例子,其中引入了许多令人期待已久的特性(虽然我没有过这样的体会),但不管你的代码是普通青年款还是文艺青年款,你都可以从被 java8 的重新组织的代码看到她的简洁之处,不得不让我对这些新入贵圈(java圈)的小鲜肉做一些记录,以便我能很好的利用他们. 最大的一个特点莫非就是引入了"函数式"编程这一个概念(都是剽窃的别的语言来的),还有那么多新奇的词语,比如"语法糖""闭包""显式|隐式函数&qu

Java8 Lambda - Functioanl Interface 函数式接口

在java 8 里面新增了functional interface 这个概念.并且添加了新的annotation @FunctionalInterfaceI 1 什么是functional interface 函数式接口了? functional interface : functional interface only have 1 abstract method. 这就是函数接口的定义.简单明白,函数接口其实就是一个抽象方法的接口(interface). 2 函数式接口的类型 这里我只介绍基

Java 8 函数式接口 - Functional Interface

阅读目录 什么是函数式接口(Functional Interface) 函数式接口用途 关于@FunctionalInterface注解 函数式接口里允许定义默认方法 函数式接口里允许定义静态方法 函数式接口里允许定义java.lang.Object里的public方法 JDK中的函数式接口举例 参考资料 什么是函数式接口(Functional Interface) 其实之前在讲Lambda表达式的时候提到过,所谓的函数式接口,当然首先是一个接口,然后就是在这个接口里面只能有一个抽象方法. 这种

java8之lambda表达式(函数式接口)

在Java中有许多已有的接口都需要封装代码块,例如:Runnable或者Comparator.lambda表达式与这些接口是向后兼容的.对于只包含一个抽象方法的接口,你可以通过lambda表达式来创建该接口的对象,这种接口被称为函数式接口.注意:Java8中接口可以声明非抽象的方法. 为了演示函数式接口转换,我们以Arrays.sort方法为例.该方法的第二个参数需要一个Comparator接口(该接口只含有一个方法)的实例.接下来我们编写一个简单的lambda表达式: Arrays.sort(

java1.8函数式接口

package com.wzy.t1; @FunctionalInterface//此注解用来声明此接口为函数式接口 public interface People { /** * 1.函数式接口只能有一个抽象方法,而不是指只能有一个方法, * 因为equals()方法在java.lang.Object中已经实现,所以也符合函数式规范 * 2.如果这个接口内只有一个抽象方法,那么即使不写@FunctionalInterface,也被看作是一个函数式接口 * 3.可以有很多默认的方法 * 4.使用