Java8函数式编程之三:函数式接口

2017-10-31  本文已影响78人  linkinparkzlz

上一篇博客Java8函数式编程之二 : Lambda表达式 - 简书 介绍了Lambda表达式,最后也留下了一个问题,就是Lambda到底用在什么地方,以及什么是函数式接口?

还记得我们在第一篇博客中定义的这个接口吗?

public interfaceTradePredicate {

booleantest(Trade trade);

}

这就是一个函数式接口。那么怎样去鉴别一个接口是否是函数式接口呢?

简单的说:函数式接口就是只定义了一个抽象方法的接口。比如JavaAPI中的Comparator 和Runnable。

public interface Comparator{

int compare(T o1, T o2);

}

public interface Runnable{

void run();

}

————————

注意:函数式接口是只定义“一个抽象方法”的接口,只定义一个抽象方法并代表没有其他方法,后面我们知道,接口里还可以有默认方法。

————

我们也可以说,加上注解@FunctionalInterface的接口(只有一个抽象方法的接口),就是一个函数式接口。

——————

关于函数式接口,注意以下几点:

1.如果一个接口只有一个抽象方法,那么该接口就是函数式接口。

2.如果我们在某个接口上声明了@FunctionalInterface注解,那么编译器就会按照函数式接口的定义来要求该接口。

3.如果某个接口只有一个抽象方法,但我们并没有给该接口声明@FunctionalInterface注解,那么编译器依旧会将其看作是函数式接口。

————————————

@FunctionalInterface

public interfaceMyInterface {

public voidtest();

publicString myString();

}

这样会报错;

Invalid'@FunctionalInterface'annotation; MyInterface is not a functional interface

——————————

但是!

@FunctionalInterface

public interfaceMyInterface {

public voidtest();

publicString toString();

}

如果是这样,就不会报错,为什么呢?

————————

我们看看Java Document文档是怎么说的:

Ifan interface declares an abstract method overriding one of the

public methods of {@codejava.lang.Object}, that also does

notcount toward the interface's abstract method count

since any implementation of the interface will have an

implementation from {@codejava.lang.Object} or elsewhere.

简单的解释就是:当你重写的方法是Object类的方法时,并不会算在“抽象方法”内。

————————————

函数式接口的实例可以通过Lambda表达式,方法引用或者构造方法引用来创建。

————————————

我们来看看使用各种方式来遍历集合,对比其特点:

public classTest {

public static voidmain(String[] args) {

List list = Arrays.asList(1,2,3,4,5,6,7,8,9);

//使用for循环

for(inti =0; i < list.size(); ++i) {

System.out.print(list.get(i));

}

//增强的for循环

for(Integer i : list) {

System.out.print(i);

}

//匿名内部类

list.forEach(newConsumer() {

@Override

public voidaccept(Integer integer) {

System.out.print(integer);

}

});

//Lambda表达式

list.forEach(i -> {

System.out.print(i);

});

}

}

————————————————————

你可能对forEach()这个方法并不熟悉,我们可以看看它的Javadoc说明。

/**

* Performs the given action for each element of the {@codeIterable}

* 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.

通过对forEach()方法注释的理解,我们发现其执行的的是一种给定的动作。

————————

那为何不继续看看forEach()方法的实现呢?

default voidforEach(Consumer action) {

Objects.requireNonNull(action);

for(Tt :this) {

action.accept(t);

}

}

————————

问题1:

你可能会疑惑,default是什么呢?好像以前没有这个关键字,并且这个方法是有实现的。这就是我们先前说的默认方法,Java8中,接口里是可以有方法实现的,这种方法就是默认方法。这是个很好的设计,即有利于Java8的新的特性的加入,又很好的兼容了以前的Java版本。

——————————

问题2:forEach()里接收的参数类型是Consumer, 这个又是什么呢,有什么用呢?

这个当然是函数式接口,不够是Java8为我们提供的,还有类似的接口如Predicate,Function等等。在下一篇博客中将详细介绍它们。

上一篇下一篇

猜你喜欢

热点阅读