热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Java8Lambda基础之函数接口

什么是函数接口?函数接口英文全称是FunctionalInterface,是一种可用于Lambda表达式的接口,该概念在JDK8首次被提出,关于FunctionalInterfac

什么是函数接口?

函数接口英文全称是FunctionalInterface,是一种可用于Lambda表达式的接口,该概念在JDK 8首次被提出,关于FunctionalInterface JDK官方文档的解释是

* Conceptually, a functional interface has exactly one abstract

* method. Since {@linkplain java.lang.reflect.Method#isDefault()

* default methods} have an implementation, they are not abstract. If

* an interface declares an abstract method overriding one of the

* public methods of {@code 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 from {@code java.lang.Object} or elsewhere.

从中我们得知一个functional interface 有且只有一个抽像方法。比如我们常见的Runnable接口

@FunctionalInterface
public interface Runnable {
/** * When an object implementing interface Runnable is used * to create a thread, starting the thread causes the object's * run method to be called in that separately executing * thread. *

* The general contract of the method run is that it may * take any action whatsoever. * * @see java.lang.Thread#run() */
public abstract void run();
}

但functional interface中并不限制有非抽像方法存在比如Java8 后引进的default方法。以Stream.forEach中常用的Consumer接口为例,里面就带了一个andThen的非抽像方法。

@FunctionalInterface
public interface Consumer<T> {
/** * Performs this operation on the given argument. * * @param t the input argument */
void accept(T t);
default Consumer<T> andThen(Consumer super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}

除此之外functional interface还不限制存在Object类中定义的公有接口的方法,因为这本来就是Interface中隐式声明的。即使显示声明也不会计算进抽像方法中。比如JDK自带的Comparator里面就定义了两个抽像方法,但因为equals是Object类公有的方法。所以equals方法不会被计算进抽像方法个数。Comparator依然是个function interface。

@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2); boolean equals(Object obj);
}

所以总的来说,函数接口是只有一个抽像方法,但可以抽像定义Object类公有方法和存在default方法的一类接口。

创建实例

一般接口实例的创建是implement该接口的对象,函数接口也不例外。但函数接口的特别之外在于Lambda表达式方面的应用,它可以被lambda expression、method references、 constructor references创建。可以说lambda表礞式创建的所有对象都是函数接口实例。

下面是三种创建的例子

Runnable runnable = () -> System.out.println("lambda expression"); //lambda expression Comparator<String> comparing = Comparator.comparing(String::length); //method references BiConsumer<File, String> fileStringBiConsumer = File::new; //constructor references

另外函数接口之所以限制只有一个抽像方法的原因,是因为这个抽像方法代表了lambda expression要实现的函数类型。如果有多个抽像方法lambda expression根本不知道实现的是哪个方法。另外抽像方法的参数个类、参数类型以及返回值、异常定义是编译器进行类型推断的依据。

泛型问题

比如有以下三个接口:

@FunctionalInterface
public interface Foo extends Foo1, Foo2 {
void bar(List args);}
interface Foo1 {
void bar(List<String> args);
}
interface Foo2 {
void bar(List<Integer> args);
}

看上去Foo 继承了Foo1, Foo2两个接口。这两个接口又各自了一个抽像方法,Foo又定义了一个抽像方法。这样Foo就有三个抽像方法了,不可能是一个funtion interface。但实际上因为Java泛型会有一个类型擦除动作。所以这三个接口的方法实际都是:

void bar(List args);

这样Foo的抽像方法相当于覆盖了Foo1,Foo2的接口中的抽像方法,就是只有一个。所以Foo可以看作是function inferface。


推荐阅读
author-avatar
lily0407520
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有