函数式接口 —— Functional Interface

函数式接口(Functional Interface)的定义:

  • 所谓的函数式接口,首先是一个接口,而后在这个接口里面只能有一个抽象方法
  • 这种类型的接口也称为SAM接口,即Single Abstract Method Interfaces
  • Java 8为函数式接口引入了一个新注解@FunctionalInterface,主要用于编译级错误检查,加上该注解,当你写的接口不符合函数式接口定义的时候,编译器会报错

简单示例:java

interface MyFunctionInterfaceOne<T>{
    void saySomething(T t);
}

上面就符合成为函数式接口的条件,即接口里面只有一个抽象方法,若是咱们在接口中再加上一个抽象方法:web

interface MyFunctionInterfaceOne<T>{
    void saySomething(T t);
    void saySomething2(T t);
}

这个时候该接口就不是一个函数式接口了,已经变成一个普通的接口,固然,此时也不会报错。可是,若是给该接口加上注解@FunctionalInterface,变成:编程

@FunctionalInterface
interface MyFunctionInterfaceOne<T>{
    void saySomething(T t);
}

那么此时,在该接口下就不能再增长抽象方法,不然编译时就会出错。
固然,除了只能有一种抽象方法外,函数式接口内还能够有其余三种类型的方法:dom

  • 默认方法
  • 静态方法
  • Object里的public方法

示例以下:ide

@FunctionalInterface
interface MyFunctionInterfaceTwo<T>{

    void saySomething(T t);

    /** * 函数式接口里是能够包含默认方法,由于默认方法不是抽象方法,其有一个默认实现,因此是符合函数式接口的定义的; */
    default void sayHello(){
        System.out.println("hello");
    }

    /** * 函数式接口里是能够包含静态方法,由于静态方法不能是抽象方法,是一个已经实现了的方法,因此是符合函数式接口的定义的; */
    static void sayGoodbye(){
        System.out.println("goodbye");
    }

    /** * 函数式接口里是能够包含Object里的public方法,这些方法对于函数式接口来讲,不被当成是抽象方法(虽然它们是抽象方法); * 由于任何一个函数式接口的实现,默认都继承了Object类,包含了来自java.lang.Object里对这些抽象方法的实现; * @param anObject * @return */
    @Override
    boolean equals(Object anObject);

}

函数式接口的使用

@Slf4j
public class FunctionalInterfaceDemo {

    @Test
    public void test1(){

        //lambda表达式不能是泛型的,可是与lambda表达式关联的函数式接口能够是泛型的
        MyFunctionInterfaceOne<String> a = x -> log.info(x);
        MyFunctionInterfaceTwo<String> b = x -> System.out.println(x);
		
		//将函数式接口做为形参传入方法
        FunctionalInterfaceDemo.arraySay(b, Arrays.asList("zao","mian","bao"));
    }

    public static <T> void arraySay(MyFunctionInterfaceTwo<T> operation , List<T> list ){
        if (list instanceof RandomAccess){
            for (int i = 0; i < list.size(); i++) {
                operation.saySomething(list.get(i));
            }
        }else {
            Iterator<T> iterator = list.iterator();
            for (int i = 0; i < list.size(); i++) {
                T next = iterator.next();
                operation.saySomething(next);
            }
        }
    }

}

函数式接口的做用

在上面的示例中,咱们将函数式接口做为形参传入arraySay方法,而后在arraySay这样调用了函数式接口中的方法:svg

operation.saySomething(list.get(i));

而后就会出现这样的状况,在咱们没有传入函数式接口参数的参数值时,该方法具体如何执行咱们是不知道的,只有当咱们使用了Lambda表达式编写了实现的动做或者说具体的操做后,咱们才知道arraySay最终会作些什么,因此函数式接口的出现给了方法极大的拓展空间,使代码之间弱耦合,同时实现了将一个动做做为参数传入到方法中,为Java的函数式编程作出了巨大的贡献。函数式接口、Lambda表达式、方法引用、Steam流一块儿实现了Java的函数式编程。函数式编程

Java8以前就已经存在的函数式接口

这里只列出平时常常使用和接触到的接口函数

接口 做用
Runnable 声明一个线程的具体实现没有返回值,配合Thread使用
Comparator 声明一个比较方式,通常配合集合排序使用
InvocationHandler 声明一个代理对象方法的额外具体实现,配合Proxy一块儿使用
Callable 声明一个线程的具体实现且有返回值,配合Future或FutureTask使用

Java8以后出现的几种核心函数式接口

新增的函数式接口都在java.util.function包下ui

接口 定义
Consumer 消费型接口,接受参数,无返回值类型的接口
Function 函数型接口,输入参数,输出结果
Supplier 供给类型得接口,只有返回值,没有入参
Predicate 断言型接口,输入参数,输出boolean类型的返回值

Consumerthis

接口 定义
Consumer 表明了接受一个输入参数而且无返回的操做
BiConsumer<T,U> 表明了一个接受两个输入参数的操做,而且不返回任何结果
DoubleConsumer 表明一个接受double值参数的操做,而且不返回结果
IntConsumer 接受一个int类型的输入参数,无返回值
LongConsumer 接受一个long类型的输入参数,无返回值
ObjDoubleConsumer 接受一个object类型和一个double类型的输入参数,无返回值
ObjIntConsumer 接受一个object类型和一个int类型的输入参数,无返回值
ObjLongConsumer 接受一个object类型和一个long类型的输入参数,无返回值

Function

接口 定义
Function<T,R> 接受一个输入参数,返回一个结果
BiFunction<T,U,R> 表明了一个接受两个输入参数的方法,而且返回一个结果
DoubleFunction 表明接受一个double值参数的方法,而且返回结果
DoubleToIntFunction 接受一个double类型输入,返回一个int类型结果
DoubleToLongFunction 接受一个double类型输入,返回一个long类型结果
IntFunction 接受一个int类型输入参数,返回一个结果
IntToDoubleFunction 接受一个int类型输入,返回一个double类型结果
IntToLongFunction 接受一个int类型输入,返回一个long类型结果
LongFunction 接受一个long类型输入参数,返回一个结果
LongToDoubleFunction 接受一个long类型输入,返回一个double类型结果
LongToIntFunction 接受一个long类型输入,返回一个int类型结果
ToDoubleBiFunction<T,U> 接受两个输入参数,返回一个double类型结果
ToDoubleFunction 接受一个输入参数,返回一个double类型结果
ToIntBiFunction<T,U> 接受两个输入参数,返回一个int类型结果
ToIntFunction 接受一个输入参数,返回一个int类型结果
ToLongBiFunction<T,U> 接受两个输入参数,返回一个long类型结果
ToLongFunction 接受一个输入参数,返回一个long类型结果
BinaryOperator 表明了一个做用于于两个同类型操做符的操做,而且返回了操做符同类型的结果
DoubleBinaryOperator 表明了做用于两个double值操做符的操做,而且返回了一个double值的结果
DoubleUnaryOperator 接受一个参数同为类型double,返回值类型也为double
IntBinaryOperator 接受两个参数同为类型int,返回值类型也为int
IntUnaryOperator 接受一个参数同为类型int,返回值类型也为int
LongBinaryOperator 接受两个参数同为类型long,返回值类型也为long
LongUnaryOperator 接受一个参数同为类型long,返回值类型也为long
UnaryOperator 接受一个参数为类型T,返回值类型也为T

这里Operator结尾的接口都继承了Function接口,都是属于有输入,有返回值的函数式接口类型

Supplier

接口 定义
Supplier 无参数,返回一个结果
BooleanSupplier 表明了boolean值结果的提供方
DoubleSupplier 表明一个double值结构的提供方
IntSupplier 无参数,返回一个int类型结果
LongSupplier 无参数,返回一个结果long类型的值

Predicate

接口 定义
Predicate 接受一个输入参数,返回一个布尔值结果
BiPredicate<T,U> 表明了一个两个参数的boolean值方法
DoublePredicate 表明一个拥有double值参数的boolean值方法
IntPredicate 接受一个int输入参数,返回一个布尔值的结果
LongPredicate 接受一个long输入参数,返回一个布尔值类型结果

几个使用到函数式接口的地方

Iterable中的forEach方法

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

Collections中的sort方法

public static <T> void sort(List<T> list, Comparator<? super T> c) {
    list.sort(c);
}

NativeLibLoader中的静态代码块

static {
    AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
        verbose = Boolean.getBoolean("javafx.verbose");
        return null;
    });
}