美文网首页
Java8函数式编程之三:函数式接口

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

作者: linkinparkzlz | 来源:发表于2017-10-31 22:35 被阅读78次

    上一篇博客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等等。在下一篇博客中将详细介绍它们。

    相关文章

      网友评论

          本文标题:Java8函数式编程之三:函数式接口

          本文链接:https://www.haomeiwen.com/subject/lwbipxtx.html