1、简介
1.1、作用
该接口自1.8被引入,存在于java.util.function包中,用于配合lambda表达式,完成函数式编程的需求。该接口表示一个函数,它接受一个参数,并返回一个结果,就像 fn(T)=R。
1.2、接口签名
@FunctionalInterface
public interface Function<T, R> {...}
其中:
- <T> 表示函数入参参数类型。
- <R> 表示函数输出参数类型。
2、常用方法
Function接口,由以下四个方法组成。
2.1、apply
- 方法签名:
R apply(T t);
- 方法说明:apply方法是接口中的抽象方法,接收T类型参数,返回R类型结果。在Function接口中,apply方法是便是lambda表达式的抽象。
示例:
(1).简单示例:输入一个整数,除2后将其返回。
import java.util.function.Function;
public class Main {
public static void main(String args[])
{
Function<Integer, Double> half = a -> a / 2.0;
System.out.println(half.apply(10));
}
}
输出:
5.0
(2).简单示例:输入Object对象,执行其toString()并返回。
import java.util.function.Function;
public class Main {
public static void main(String[] args) {
Function function = s -> s.toString();
System.out.println(function.apply("hello"));
System.out.println(function.apply(12345));
}
}
输出:
hello
12345
在第二个示例中,声明Function时,并未指定类型,所以apply可以接收任何Object对象,并且执行其toString(),然后返回。
2.2、addThen
- 源码:
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
- 源码分析:
如上,andThen是一个默认实现方法,它接收一个Function类型的参数after,并且需要确保after不能为空,否则将向上抛出NPE,然后是一段lambda表达式所表示的Function。lambda表达式体中,只有一句代码:after.apply(apply(t)),主要的作用是在执行完this.apply后,再执行after.apply,所以最后返回的结果是一对组合函数。
示例:
(3) 简单示例:在简单示例(2)的基础上,添加andThen。
import java.util.function.Function;
public class Main {
public static void main(String[] args) {
Function function = s -> s.toString();
function = function.andThen(a -> a + " ---> after");
System.out.println(function.apply("hello"));
System.out.println(function.apply(12345));
}
}
输出:
hello ---> after
12345 ---> after
2.3、compose
- 源码
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
- 源码分析
compose与andThen类似,不同的是compose是在执行this.apply()之前执行before.apply(),最后返回一组组合函数。
示例
(4)简单示例:在简单示例(3)的基础上添加compose。
import java.util.function.Function;
public class Main {
public static void main(String[] args) {
Function function = s -> s.toString();
function = function.andThen(a -> a + " ---> after");
function = function.compose(a -> "compose -- > " + a);
System.out.println(function.apply("hello"));
System.out.println(function.apply(12345));
}
}
输出:
compose -- > hello ---> after
compose -- > 12345 ---> after
2.4、identity
- 源码
static <T> Function<T, T> identity() {
return t -> t;
}
- 源码分析
identity()方法是一个静态方法,不接收任何参数,返回一个Function<T,T>对象(Function<T,T> 表示apply()方法的入参类型与出参类型一致)。此Function对象的作用可以用fn(x) = x表示,也就是在执行apply(x)时,原样返回x。
示例
(5)简单示例:identity示例。
import java.util.function.Function;
public class Main {
public static void main(String[] args) {
Function<String, String> f = Function.identity();
Function<String, String> f1 = Function.identity();
System.out.println(f1.apply("identity demo ~"));
Function f2 = Function.identity();
System.out.println(f2.apply("identity demo ~"));
Date now = (Date) f2.apply(new Date());
System.out.println(now);
}
}
输出:
identity demo ~
identity demo ~
Sat Aug 10 12:34:28 CST 2019
在上面示例中,f2没有指定Function泛型类型,默认为Function<T,T>,所以在将f2.apply(new Date())赋值给now时,需求强制转换为Date对象。
3、小结
本篇介绍了Function的作用与四个方法,其中apply方法是需要我们去实现,一般我们会用lambda表示。addThen()方法和compose()方法是默认方法,分别与apply方法组成一对组合函数,addThen()在apply()之后执行,compose()方法在apply()之前执行。identity()方法返回一个类似于fn(x) = x的Function。
在编程过程中,如果你有类似于下面这种接口:
@FunctionalInterface
public interface Foo {
String method(String string);
}
你应该要优先考虑使用标准函数接口:Function,而不是自己再去定义。
同时java.util.function包中还有许多常见的函数接口,如BiConsumer、BiFunction等,在自己编写函数接口时,可以先去此包下探索一番再来考虑是否要自己编写。
参考
- https://www.baeldung.com/java-8-lambda-expressions-tips
- https://www.geeksforgeeks.org/function-interface-in-java-with-examples