首言:
函数式编程作为一种编程范式,在科学领域,是一种编写计算机程序数据结构和元素的方式,它把计算过程当做是数学函数的求值,而避免更改状态和可变数据。而Java中的函数式编程体现就是Lambda,所以函数式接口就是可以适用于Lambda使用的接口。只有确保接口中有且仅有一个抽象方法,Java中的Lambda才能顺利地进行推导。
一、函数式接口
特点
- 接口有且仅有一个抽象方法
- 允许定义静态方法
- 允许定义默认方法
- 允许java.lang.Object中的public方法
- 注解@FunctionInterface不是必须的,如果一个接口符合"函数式接口"定义,那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上了@FunctionInterface,那么编译器会报错
基于以上函数式接口特点,可以想到Runnable接口就是一个最典型的函数式接口。接口中只有一个run抽像方法。JDK8中查看Runnable源码,可以看到在接口上加上了@FunctionInterface注解,标识此接口为函数式接口。
@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
二、内置函数式接口
lambda表达式实例化该接口,达到简化写法的目的。在JDK8中内置了四个核心的函数式接口来适用我们通用编程需要。
函数式接口 | 方法 | 参数类型 | 返回类型 | 作用 |
Consumer<T> 消费型接口 | void accept(T t) | T | void | 对T类型的参数进行操作 |
Supplier<T> 供给型接口 | T get() | 无 | T | 操作数据,返回T类型的结果 |
Function<T, R> 函数型接口 | R apply(T t) | T | R | 对T类型参数进行操作,并返回R类型的结果 |
Predicate<T> 断定型接口 | boolean test(T t) | T | boolean | 确定T类型参数是否满足某约束,并返回boolean值 |
1、Consumer消费型接口
该接口提供一个accept方法,接受一个参数,无返回值。
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
我们看个例子,定义了一个lambda实现体,通过accept传入参数,打印传入的参数信息
@Test
public void test() {
String str = "伴学编程";
Consumer consumer = t -> System.out.println(t);
consumer.accept(str);
}
2、Function函数型接口
该接口提供一个apply方法,接受一个参数,有返回值。
@FunctionalInterface
public interface Function<T, R> {
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);
我们看个例子,定义了一个lambda实现体,通过apply方法传入参数,打印传入的参数信息。
@Test
public void test() {
String str = "伴学编程";
Function function = t -> t;
System.out.println(function.apply(str));
}
3、Supplier供给型接口
该接口提供一个get方法,无参数,有返回值。
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
我们看个例子,定义了一个lambda实现体,通过get方法返回并打印返回信息。
@Test
public void test() {
String str = "伴学编程";
Supplier supplier = () -> str;
System.out.println(supplier.get());
}
4、Predicate断言型接口
该接口提供一个test方法,传入一个参数,返回boolean型值。
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
我们看个例子,定义了一个lambda实现体,通过test方法传入参数,返回并打印判断结果。
@Test
public void test() {
String str = "伴学编程";
Predicate predicate = t -> "伴学编程".equals(t);
System.out.println(predicate.test(str));
}
上面是通用比较典型的接口,有同伴可能需要一个函数式接口操作两个参数,并有返回值。JDK8也内置这些子接口。
函数式接口 | 方法 | 参数类型 | 返回类型 | 作用 |
BiFunction<T , U, R > | R apply(T t, U u) | T, U | R | 对 T, U 类型的参数进行操作,并返回R类型的结果 |
UnaryOperator<T> (Function 子接口) | T apply(T t) | T | T | 对 T类型的参数进行一元运算,并返回R对象的结果 |
BinaryOperato<T,R> (BiFunction 子接口) ) | T apply(T t1, T t2) | T, T | T | 对T类型的参数进行二元运算,并返回T类型的结果 |
BiConsumer<T, U> | void accept(T t, U u) | T, U | void | 对T,作 |
ToIntToIntFunction<T> ToLongFunction<T> ToDoubleFunction<T> | int(long,double) applyAsInt(T value) | T | int, long, double | 计 算 int 、 long 、double值的函数 |
IntFunction<R> LongFunction<R> DoubleFunction<R> | R apply(int(long,double) value) | int, long, double | R | 参数分别为int、long、double 类型的函数 |
三、默认方法、静态方法
JDK7中,接口能定义全局静态属性与抽像方法。JDK8的接口现在可以定义默认方法与静态方法。
1、默认方法
简单说,默认方法就是接口可以有实现方法,而且不需要实现类去实现其方法。
我们只需在方法名前面加个 default 关键字即可实现默认方法。
@FunctionalInterface
public interface LambdaService {
boolean isAvailable(String name, Integer age);
default String getName() {
return "伴学编程";
}
}
2、静态方法
Java 8 的另一个特性是接口可以声明静态方法,在方法返回类型前加static关键字即可实现静态方法。
@FunctionalInterface
public interface LambdaService {
boolean isAvailable(String name, Integer age);
static String getName() {
return "伴学编程";
}
}
四、小结
JAVA 8 之前接口定义的抽像方法一般是用匿名类实现的,JDK8就可以使用Lambda表达式来表示该接口的一个实现,而函数式接口可以对现友好地支持lambda表达式,将函数参数形式传入方法中,使用代码编程简洁、优雅。