Java系列教程一起爪哇Java 8——函数式接口

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java系列教程一起爪哇Java 8——函数式接口相关的知识,希望对你有一定的参考价值。

引言

目前由于系统已经全面切换为JDK8,所以有必要系统的了解一下Java8的一些新特性,以便后续在日常工作中可以使用一些高级特性来提高编程效率。

因为Java8引入了函数式接口,在java.util.function包含了几大类函数式接口声明。这里第一篇主要研究一下Function相关的接口。

FunctionalInterface注解

Java8的新引入,包含函数式的设计,接口都有@FunctionalInterface的注解。就像这个注解的注释说明一样,它注解在接口层面,且注解的接口要有且仅有一个抽象方法。具体就是说,注解在Inteface上,且interface里只能有一个抽象方法,可以有default方法。因为从语义上来讲,一个函数式接口需要通过一个***逻辑上的***方法表达一个单一函数。那理解这个单一就很重要了,单一不是说限制你一个interface里只有一个抽象方法,单是多个方法的其他方法需要是继承自Object的public方法,或者你要想绕过,就自己实现default。函数式接口自己本身一定是只有一个抽象方法。同时,如果是Object类的public方法,也是不允许的。官方的说明翻译如下:

如果一个接口I,I有一组抽象方法集合M,且这些方法都不是Object类的public签名方法,那么如果存在一个M中的方法m,满足:

  • m的签名是所有M中方法签名的子签名。

  • m对于M中的每个方法都是返回类型可替换的。 此时,接口I是一个函数式接口。

怎么理解,看几个例子。

比如:你声明一个接口:

@FunctionalInterfacepublic interface Func {}

这会编译错,编译器会告诉你*no target method*。而如果加一个方法:

@FunctionalInterfacepublic interface Func {    void run();
}

这就OK了,一个函数式接口声明好了。再加一个呢?

@FunctionalInterfacepublic interface Func {    void run();    void foo();
}

不ok,明确说了只有一个抽象方法嘛。但是如果换一种函数签名:

@FunctionalInterfacepublic interface Func {    boolean equals(Object obj);
}

错误依旧,因为这个方法签名是Object类的public方法。而再改一下:

@FunctionalInterfacepublic interface Func {    boolean equals(Object obj);    void run();
}

这就OK了。一个抽象方法,一个Object的public方法,相安无事。Object还有其他方法,clone方法试试会怎么样?

@FunctionalInterfacepublic interface Func {    Object clone();    void run();
}

这又不行了,因为前面明确说了,要是Object的public方法,而clone是protected的。

所以总结一句话就是:

函数式接口,有且仅有一个抽象方法,Object的public方法除外。

因为Java本身支持多接口实现,你定义一个Class可以implements多个interface。所以这个限制也没什么影响,如果想约定一个函数式接口来统一,也可以做一些默认的实现来达到一个接口多个抽象方法的目的,比如下面这种做法:
一个普通接口NonFunc:

public interface NonFunc {    void foo();    void voo();
}

函数式接口Func:

@FunctionalInterfacepublic interface Func extends NonFunc {    void run();    default void foo() {        // do something
    }    default void voo() {        // do something
    }
}

实现的测试类:

public class TestJ8FunctionalInterface implements Func {    public static void main(String[] args) {        Func func = new TestJ8FunctionalInterface();        func.run();        func.foo();        func.voo();
    }

    @Override
    public void run() {        System.out.println("run");
    }

    @Override
    public void foo() {        System.out.println("foo");
    }

    @Override
    public void voo() {        System.out.println("voo");
    }
}

函数式接口的一大特性就是可以被lambda表达式和函数引用表达式代替。也就是说声明这样的接口,是可以灵活的以方法来传参。看个例子:

public class TestJ8FunctionalInterface2 {    public static void main(String[] args) {
        TestJ8FunctionalInterface2 testJ8FunctionalInterface2 = new TestJ8FunctionalInterface2();        // lambda
        testJ8FunctionalInterface2.test(10, () -> System.out.println("A customed Func."));        // method reference
        testJ8FunctionalInterface2.test(100, testJ8FunctionalInterface2::customedFunc);
    }    public void customedFunc() {
        System.out.println("A customed method reference.");
    }    public void test(int x, Func func) {
        System.out.println(x);
        func.run();
    }
}

上面例子列举了一个lambda模式和一个方法引用模式,这样就可以利用函数式编程强大的能力,将方法作为参数了。

阅读全文请点击:http://click.aliyun.com/m/9152/


本文出自 “12466150” 博客,请务必保留此出处http://12476150.blog.51cto.com/12466150/1890430

以上是关于Java系列教程一起爪哇Java 8——函数式接口的主要内容,如果未能解决你的问题,请参考以下文章

了解一下 Java 8 Predicate 函数接口

JAVA 8 新特性 函数式接口

恕我直言你可能真的不会java第8篇-函数式接口

Java8新特性及实战视频教程完整版

爪哇。隐式超级构造函数 Employee() 未定义。必须显式调用另一个构造函数[重复]

Java 8 Function 函数接口