什么是函数式接口
引用两个地方的定义来尝试地解答下什么是函数式接口
An Interface that contains exactly one abstract method is known as functional interface. It can have any number of default, static methods but can contain only one abstract method. It can also declare methods of object class.
Functional Interface is also known as Single Abstract Method Interfaces or SAM Interfaces. It is a new feature in Java, which helps to achieve functional programming approach.
上面是javapoint)网站的定义,总结下几点
- 只能有一个抽象函数的接口
- 可以有任一多默认的静态的方法
- 可以有Object类已经声明的方法,因为所有的类都是Object的子类
An informative annotation type used to indicate that an interface type declaration is intended to be a functional interface as defined by the Java Language Specification. Conceptually, a functional interface has exactly one abstract method. Since default methods have an implementation, they are not abstract. If an interface declares an abstract method overriding one of the public methods of
java.lang.Object
, that also does not count toward the interface’s abstract method count since any implementation of the interface will have an implementation fromjava.lang.Object
or elsewhere.Note that instances of functional interfaces can be created with lambda expressions, method references, or constructor references.
If a type is annotated with this annotation type, compilers are required to generate an error message unless:
- The type is an interface type and not an annotation type, enum, or class.
- The annotated type satisfies the requirements of a functional interface.
However, the compiler will treat any interface meeting the definition of a functional interface as a functional interface regardless of whether or not a
FunctionalInterface
annotation is present on the interface declaration.
再来看看FunctionalInterface
中的javadoc,大差不差是一个意思,不过还是能总结出额外的一些小知识点
- 函数式接口的实例可以使用lambda表示,方法引用或者构造函数引用
- 带有这个注解的type表示这是接口,而不是注解,枚举或者类
- 函数式接口可以不带这个注解,但是带上了这个注解却不是函数式接口的话,编译器将会报错
自定义函数式接口
这里插一句题外话,如果上网搜索一把函数式接口,可以发现好多知识,那现在写这篇文章仅仅是在重复的炒冷饭吗,其实不是的。网上很多文章千篇一律都是讲了java中常用的函数式接口,就那几样,而且讲得云里雾里的,完全不是那种新手入门的文章,至少我是看不懂。正是这样,我觉得可以写下我对函数式接口的理解,接下来会从自定义函数式接口切入。
想表达的东西很简单
- 自定义一个IAnaimal的接口,里面只有一个抽象方法
talk()
。 - 两个具体的实现类实现这个方法。
- 还有主方法调用
talk()
。
IAnimal.java
Cat.java
Dog.java
Main.java
但是有些时候不想新建一个类,比如接口比较简单,实现也不复杂,新建一个类可能会冗余,此时有的同学就会想到使用匿名内部类。
说到匿名内部类,那就代表可以用lambda表达式再次简化
这样一简化后IAnimal就已经是一个函数接口了,而整个例子也就是自定义函数式接口,所以可以发现它的本质还是一个接口,只不过实现类从一个完整的类变成了通过函数去实现。
java中常用的函数式接口
上面讲了一个简单的自定义函数式接口的例子,接下来再看下jdk本身就声明的四大函数式接口。
函数式接口 | 参数类型 | 返回类型 | 用途 | 主要方法 |
---|---|---|---|---|
Consumer |
T | void | 消费类型为T的对象 | void accept(T t) |
Supplier |
无 | T | 返回类型为T的对象 | T get() |
Function |
T | R | 操作类型为T的对象,返回R类型的对象 | R apply(T t) |
Predicate |
T | boolean | 确定类型为T的对象是否满足约束,返回boolean | boolean test(T t) |
Consumer
输出如下
Supplier
对于supplier来说,实在是找不到啥比较好的例子,或者找到的例子都十分简单,这里稍微说下supplier的懒加载特性,看下输出
Function
输出:
Predicate
输出:
破产版实现ArrayList中的forEach
可能新手同学们没太听过函数式接口,但是平常编码开发中的list里的forEach入参就是一个函数式接口
接下来参考源码实现一个破产版的List和List中的forEach,总共有以下几个步骤
- 新建一个Student对象
- 自定义一个list,里面有个Student数组存元素,还有一个add方法和forEach方法(使用Consumer)
- 改造方法,自定义一个函数式接口替代Consumer
Student
MyList
ForEachMain
看下输出:
IAnyway
自定义一个函数式接口,本质上就是Consumer,然后类名和方法名改了一下,这样的目的是告诉新手同学jdk中的4大函数式接口不是什么神奇的东西,它们本质上就是接口,只不过是jdk总结了我们常用的场景来声明了这些函数式接口,避免了重复去声明一样作用的函数式接口。
定义了接口后,在来看看MyList
类
使用的地方也修改一下
输出:
思考
洋洋洒洒也写了一点,写完发现更迷糊了,我是知道函数式接口是啥了,甚至在工作的编码中也强迫自己用了一把函数接口,还合入了公司的代码仓。但是,什么时候什么情况下使用函数接口还一直困惑着我,包括google,baidu,statckoverflow都没有一个比较好的答案。于目前的我而言,函数式接口似乎和匿名内部类,和lambda表达式是一个东西。
参考文献
Java 8 Functional Interfaces – javatpoint
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net