本文概要

什么是函数式接口?
如何定义函数式接口?
常用的函数式接口
函数式接口语法注意事项
总结

1. 什么是函数式接口?

函数式接口其实本质上还是一个接口,但是它是一种特殊的接口:SAM类型的接口(Single Abstract Method),在这个接口里面只能有一个抽象方法。

当开发者在编写Lambda表达式时,也会随之被编译成一个函数式接口。Lambda表达式只是语法糖,我们只要理解函数式接口,才能读懂和用好Lambda表达式。

2. 如何定义函数式接口?

@FunctionalInterface
public interface FunctionDemo {

    void get(String str);
}

FunctionDemo fd = str -> System.out.println("Hello " + str);

3. 常用的函数式接口

使用Lambda表达式,一定有函数式接口的支持;但是如果我们每一个Lambda表达式都要自己创建一个接口,
这样很造成很大的不便。为了避免重复造轮子,java8常用的函数式接口都帮我们定义好,拿来直接使用即可。

如果这些常用的接口不能满足需求时,这时才需要 自定义函数式接口。

下面是我们常用的几类函数式接口:

消费性函数式接口

特点:接受一个或者多个参数,没有返回值

供给型函数式接口

特点:没有参数(无参),提供返回值

函数型函数式接口

特点:接收一个或者多个参数,有返回值

断定性函数式接口

特点:接收一个或者多个参数,返回一个boolean类型

@Test
public void testCoreInter(){
    /**
     * @name 消费型接口
     * @use Consumer<T>
     * @param T 传入参数
     * @fun 接受一个参数 无返回值
     * */
    Consumer<String> con=(str)->System.out.println(str);
    con.accept("我是消费型接口!");

    /**
     * @name 供给型接口
     * @use Supplier<R>
     * @param R 返回值类型
     * @fun 无参数 有返回值
     * */
    Supplier<Date> supp=()-> new Date();
    Date date=supp.get();
    System.out.println("当前时间:"+date);

    /**
     * @name 函数型接口
     * @use Function<T,R>
     * @param T 传入参数
     * @return R 返回值类型
     * @fun 接受一个参数 有返回值
     * */
    Function<String, String> fun=(str)->"hello,"+str;
    String str=fun.apply("张俊强");
    System.out.println(str);
    
    /**
     * @name 断定型接口
     * @use Predicate<T>
     * @param T 传入参数
     * @return Boolean 返回一个Boolean型值
     * @fun 接受一个参数 返回Boolean型值
     * */
    Predicate<Integer> pre=(num)->num>0;
    Boolean flag=pre.test(10);
    System.out.println(flag);
}

比如方法foreach(),入参为Consumer

default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }

4. 函数式接口语法注意事项

从SAM原则上讲,这个接口中,只能有一个函数需要被实现,但是也可以有如下例外:

默认方法:必须用default修饰,且只能是public,默认也是public。

它也是作为一种向后兼容能力而出现,旧的接口也能用到Lambda表达式中。例如,List或Collection接口是没有forEach方法的声明的。Java 8引入默认方式使得List和Collection接口能够拥有forEach方法的默认实现。实现了这些接口的类也不必再实现相同的功能了。

语法如下所示:

@FunctionalInterface  
interface A {  
     default void test() {  
           System.out.println("接口A的默认方法");  
     }  
     void test1();  
}  

静态方法

函数式接口中可以有静态方法,一个或者多个静态方法不会影响SAM接口成为函数式接口,并且静态方法可以提供方法实现

@FunctionalInterface  
interface TestStaticMethod {  
     //这是一个抽象方法  
     void test();  
     //静态方法,不是抽象方法  
     static void test1() {  
           System.out.println("接口里的静态方法!");  
     }  
}  

      
      
      

如果接口显示声明覆盖了Object中方法,那么也不算抽象方法。

 If an interface declares an abstract method overriding one of the public methods of {@code java.lang.Object},
 that also doesnot count toward the interface's abstract method count
 since any implementation of the interface will have an implementation from {@code java.lang.Object} or elsewhere.


@FunctionalInterface
public interface DemoFunctionalInterface{
    void action();

    //Object's public methods
    String toString();
    int hashCode();
    boolean equals(Object o);
}

注解@FunctionalInterface不是必须的,如果一个接口符合”函数式接口”定义,那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上了@FunctionInterface,那么编译器会报错

5. 总结

函数式接口只能包含一个抽象方法
函数式接口可以包含Object类中所有public修饰的方法
函数工接口可以包含一个或多个静态方或默认方法

参考文献

Java8 新特性—-函数式接口,以及和Lambda表达式的关系
Java8新特性(内置的核心函数式接口)
Java8的四大核心函数式接口
java8新特性之函数式接口、lambda表达式、接口的默认方法、方法和构造函数的引用
java 8 新特性(1.函数式接口 – Functional Interface
java8 函数式接口(FunctionalInterface) [一]


tips:本文属于自己学习和实践过程的记录,很多图和文字都粘贴自网上文章,没有注明引用请包涵!如有任何问题请留言或邮件通知,我会及时回复。