函数式接口:只有一个抽象函数,可以有多个非抽象函数的接口,可以使用lambda表达式或方法引用隐式的进行接口中的方法实现。
以一个函数式接口Consumer举例说明
@FunctionalInterface
public interface Consumer<T> {
//抽象函数accept,功能为按照accept功能消费掉t,功能需要用户来定义实现
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
而我们知道Collection中有forEach
方法,他的作用是使集合中的每个元素均执行一个action(Consumer函数式接口),具体到ArrayList
中的forEach
方法实现如下:
public void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
final int expectedModCount = modCount;
final Object[] es = elementData;
final int size = this.size;
for (int i = 0; modCount == expectedModCount && i < size; i++)
action.accept(elementAt(es, i));
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
其中的action.accept(elementAt(es, i))
就是使每个元素执行action(Consumer)中的accept方法(即以定义的accept方法消费掉该元素)。
那么这个accept方法是如何定义实现的呢?
在实际使用中,如果我们想要将ArrayList
中的每个元素遍历输出则会使用
list.forEach(System.out::println);
这里就用到了方法引用System.out::println
和函数式接口。
首先该语句的第一步相当于将方法引用System.out::println
隐式的对函数式接口Consumer中的唯一抽象函数void accept(T t)
进行了实现,即此时action.accept
的功能就是println
即输出元素t。
这样就好理解了,即forEach
中的action.accept(elementAt(es, i))
就是将es[i]
输出。