Java8新特性一点通 | 回顾功能接口Functional Interface
Functional Interface
Functional Interface是什么?
功能接口是java 8中的新增功能,它们只允许一个抽象方法。这些接口也称为单抽象方法接口(SAM接口)。这些也可以使用Lambda表达式,方法引用和构造函数引用来表示。Java 8也引入了一个注释,即@FunctionalInterface
,当你注释的接口违反了Functional Interface的契约时,它可以用于编译器级错误。
Tips:如果你想强制当前接口只保留一个抽象方法,就可以使用@FunctionalInterface,它可以帮我们通过编译错误提示用户必须不能声明超过一个抽象方法
构建我们第一个默认接口:
@FunctionalInterface
public interface MyFuntinoalInterface<T> {
public void eat();
/**
* 超过一个抽象方法会编译报错,可以把下面注释去掉查看效果
*/
//public void play();
}
尝试将上例的注释去掉,可以发现,超过两个抽象方法会直接报编译错误
@FunctionalInterface
public interface MyFuntinoalInterface<T> {
public void eat();
/**
* 超过一个抽象方法会编译报错,可以把下面注释去掉查看效果
*/
public void play();
}
报如下编译异常:
功能接口的使用原则
- 在任何功能接口中只允许一种抽象方法。功能界面中不允许使用第二种抽象方法。如果我们删除@FunctionInterface注释,那么我们可以添加另一个抽象方法,但它会使接口成为非功能性接口。
- 即使省略
@FunctionalInterface
注释,功能接口也是有效的。它仅用于通知编译器在接口内强制执行单个抽象方法。 - 从概念上讲,功能界面只有一种抽象方法。由于默认方法具有实现,因此它们不是抽象的。由于默认方法不是抽象的,因此您可以根据需要随意添加默认方法到功能接口。
你可以添加多个默认方法到功能接口中,但是它不会计入抽象方法的数量:
@FunctionalInterface
public interface MyFuntinoalInterface<T> {
public void eat();
default void run(){
System.out.println("跑步");
}
default void swim(){
System.out.println("游泳");
}
}
- 功能接口里可以有多个覆盖java.lang.Objectd的抽象方法,它不会计入接口的抽象方法数量。
@FunctionalInterface
public interface MyFuntinoalInterface<T> {
public void eat();
/**
* 重写Object方法不会算入抽象方法统计
* @return
*/
@Override
public String toString();
}
JDK 中的功能接口
JDK1.8开始支持功能接口,以下可以举几个例子,功能接口主要是配合lambda表达式使用,具体介绍会在后续的lambda表达式章节也会提到
Comparator
@FunctionalInterface
public interface Comparator<T>
在JDK1.8中,主要对Comparator
接口添加了默认方法,对Comparator
实现类添加了很多新特性方法
Consumer
@FunctionalInterface
public interface Consumer<T>
相信大家查看JDK1.8源码会发现,很多类都有Consumer
这个接口存在,在JDK1.8中更多是提供各个接口支持lambda表达式使用
Iterable
public interface Iterable<T> {
/**
* Returns an iterator over elements of type {@code T}.
*
* @return an Iterator.
*/
Iterator<T> iterator();
/**
* Performs the given action for each element of the {@code Iterable}
* until all elements have been processed or the action throws an
* exception. Unless otherwise specified by the implementing class,
* actions are performed in the order of iteration (if an iteration order
* is specified). Exceptions thrown by the action are relayed to the
* caller.
*
* @implSpec
* <p>The default implementation behaves as if:
* <pre>{@code
* for (T t : this)
* action.accept(t);
* }</pre>
*
* @param action The action to be performed for each element
* @throws NullPointerException if the specified action is null
* @since 1.8
*/
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
/**
* Creates a {@link Spliterator} over the elements described by this
* {@code Iterable}.
*
* @implSpec
* The default implementation creates an
* <em><a href="Spliterator.html#binding">early-binding</a></em>
* spliterator from the iterable's {@code Iterator}. The spliterator
* inherits the <em>fail-fast</em> properties of the iterable's iterator.
*
* @implNote
* The default implementation should usually be overridden. The
* spliterator returned by the default implementation has poor splitting
* capabilities, is unsized, and does not report any spliterator
* characteristics. Implementing classes can nearly always provide a
* better implementation.
*
* @return a {@code Spliterator} over the elements described by this
* {@code Iterable}.
* @since 1.8
*/
default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
}
Iterable
虽然接口头上没有@FunctionalInterface
注解标注,它这里只有一个抽象方法,默认也是一个功能接口,在JDK1.8中新添加了支撑lambda表达式的默认方法
Evan Leung,CSDN博客砖家,ACP认证砖家,在IT行业摸滚打爬多年,经历了金融行业和移动互联网行业,参与多个大中型企业级项目设计与核心开发,曾在某一线互联网金融公司担任产品线高级技术经理,目前在某世界500强金融公司打杂。