首页 > Java基础应用 > Lambda 表达式教程 > 函数式接口概述

函数式接口概述

在 Java 里面,所有的方法参数都是有固定类型的,比如将数字 9 作为参数传递给一个方法,它的类型是 int;字符串 “9” 作为参数传递给方法,它的类型是 String。那么 Lambda 表达式的类型由是什么呢?通过本节我们学习什么是函数式接口,它与 Lambda 表达式的关系。

1. 什么是函数式接口

函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口,它可以被隐式转换为 Lambda 表达式。

Tips: 换句话说函数式接口就是 Lambda 表达式的类型。

在函数式接口中,单一方法的命名并不重要,只要方法签名和 Lambda 表达式的类型匹配即可。

Tips: 通常我们会为接口中的参数其一个有意义的名字来增加代易读性,便于理解参数的用途。

函数式接口有下面几个特点:

  1. 接口有且仅有一个抽象方法;
  2. 允许定义静态方法;
  3. 允许定义默认方法;
  4. 允许 java.lang.Object 中的 public 方法;
  5. 推荐使用 @FunctionInterface 注解(如果一个接口符合函数式接口的定义,加不加该注解都没有影响,但加上该注解可以更好地让编译器进行检查)。

我们来看函数式接口的例子:

我们将得到如下结果:

call doTest
call dodefaultMethod
call doStaticMethod
com.github.x19990416.item.TestFunctionalInterface$$Lambda$1/0x00000008011e0840@63961c42

我们通过 toString 方法可以发现,test 对象被便已成为 TestFunctionalInterface 的一个 Lambda 表达式。

2. @FunctionalInterface

接下来我们再来看下 @FunctionalInterface注解的作用:

首先我们定义一个接口 TestFunctionalInterface,包含两个方法 doTest1doTest2

interfact TestFunctionalInterface{
    //一个抽象方法
    public void doTest1();
    //另一个抽象方法
    public void doTest2();
}

此时对于编译期而言我们的代码是没有任何问题的,它会认为这就是一个普通的接口。当我们使用 @FunctionalInterface 后:

//这是一个错误的例子!!!!
@FunctionalInterface
interfact TestFunctionalInterface{
    //一个抽象方法
    public void doTest1();
    //另一个抽象方法
    public void doTest2();
}

此时,会告诉编译器这是一个函数式接口,但由于接口中有两个抽象方法,不符合函数式接口的定义,此时编译器会报错:

Multiple non-overriding abstract methods found in interface

3. 常用的函数式接口

JDK 8 之后新增了一个函数接口包 java.util.function 这里面包含了我们常用的一些函数接口:

接口 参数 返回类型 说明
Predicate T boolean 接受一个输入参数 T,返回一个布尔值结果
Supplier None T 无参数,返回一个结果,结果类型为 T
Consumer T void 代表了接受一个输入参数 T 并且无返回的操作
Function T R 接受一个输入参数 T,返回一个结果 R
UnaryOperator T T 接受一个参数为类型 T,返回值类型也为 T
BinaryOperator (T,T) T 代表了一个作用于于两个同类型操作符的操作,并且返回了操作符同类型的结果

3.1 Predicate

条件判断并返回一个Boolean值,包含一个抽象方法 (test) 和常见的三种逻辑关系 与 (and) 、或 (or) 、非 (negate) 的默认方法。

Predicate 接口通过不同的逻辑组合能够满足我们常用的逻辑判断的使用场景。

结果如下:

字符串长度很长吗:true
字符串长度很长吗:false
逻辑与的结果:true
逻辑或的结果:true

3.2 Supplier

用来获取一个泛型参数指定类型的对象数据(生产一个数据),我们可以把它理解为一个工厂类,用来创建对象。

Supplier 接口包含一个抽象方法 get,通常我们它来做对象转换。

结果如下:

Hello World

上述例子中,我们把两个 String 对象合并成一个 String。

3.3 Consumer

与 Supplier 接口相反,Consumer 接口用于消费一个数据。

Consumer 接口包含一个抽象方法 accept 以及默认方法 andThen 这样 Consumer 接口可以通过 andThen 来进行组合满足我们不同的数据消费需求。最常用的 Consumer 接口就是我们的 for 循环,for 循环里面的代码内容就是一个 Consumer 对象的内容。

结果如下:

Hello
HELLO
hello

在调用第二个 consumerString 的时候我们通过 andThen 把两个 Consumer 组合起来,首先把 Hello 全部转变成大写,然后再全部转变成小写。

3.4 Function

根据一个类型的数据得到另一个类型的数据,换言之,根据输入得到输出。

Function 接口有一个抽象方法 apply 和默认方法 andThen,通过 andThen 可以把多个 Function 接口进行组合,是适用范围最广的函数接口。

结果如下:

30
220

上述四个函数接口是最基本最常用的函数接口,需要熟悉其相应的使用场景并能够熟练使用。 UnaryOperatorBinaryOperator 作用与 Funciton 类似,大家可以通过 Java 的源代码进一步了解其作用。

4. 小结

本节,我们主要阐述了函数式接口的定义以及其与 Lambda 表达式的关系。并对新增的 java.util.function 包中常用的函数式接口进行了解释。这些接口常用于集合处理中(我们将在后续的内容进一步学习),关于函数式接口主要记住一点,那就是:

接口有且仅有一个抽象方法

本文来自互联网用户投稿,不拥有所有权,该文观点仅代表作者本人,不代表本站立场。
访问者可将本网站提供的内容或服务用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯本网站及相关权利人的合法权利。
本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站,邮箱:80764001@qq.com,予以删除。
© 2023 PV138 · 站点地图 · 免责声明 · 联系我们 · 问题反馈