咱们知道Java8的最大特性就是函数式接口。全部标注了@FunctionalInterface注解的接口都是函数式接口,具体来讲,全部标注了该注解的接口都将能用在lambda表达式上。html
/** * Represents a function that accepts one argument and produces a result. * * <p>This is a <a href="package-summary.html">functional interface</a> * whose functional method is {@link #apply(Object)}. * * @param <T> the type of the input to the function * @param <R> the type of the result of the function * * @since 1.8 */
上述描述可知: Function中传递的两个泛型:T,R分别表明 输入参数类型和返回参数类型。下面将逐个介绍Function中的各个接口:编程
接口1: 执行具体内容接口
R apply(T t);app
// 匿名类的方式实现 Function<Integer, Integer> version1 = new Function<Integer, Integer>() { @Override public Integer apply(Integer integer) { return integer++; } }; int result1 = version1.apply(20); // lamda表达式 Function<Integer, Integer> version2 = integer -> integer++; int result2 = version1.apply(20);
接口2: compose
该方法是一个默认方法,这个方法接收一个function做为参数,将参数function执行的结果做为参数给调用的function,以此来实现两个function组合的功能。ide
// compose 方法源码 default <V> Function<V, R> compose(Function<? super V, ? extends T> before) { Objects.requireNonNull(before); return (V v) -> apply(before.apply(v)); }
public int compute(int a, Function<Integer, Integer> function1, Function<Integer, Integer> function2) { return function1.compose(function2).apply(a); } // 调用上述方法 test.compute(2, value -> value * 3, value -> value * value) // 执行结果: 12 (有源码能够看出先执行before)
接口3 : andThen
了解了compose方法,咱们再来看andThen方法就好理解了,听名字就是“接下来”,andThen方法也是接收一个function做为参数,与compse不一样的是,先执行自己的apply方法,将执行的结果做为参数给参数中的function。函数
public interface Function<T, R> { default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); } }
public int compute2(int a, Function<Integer, Integer> function1, Function<Integer, Integer> function2) { return function1.andThen(function2).apply(a); } // 调用上述方法 test.compute2(2, value -> value * 3, value -> value * value) // 执行结果 : 36
Function接口虽然很简洁,可是由Function源码能够看出,他只能传一个参数,实际使用中确定不能知足需求。下面提供几种思路:ui
由于参数缘由“自带的Function”函数必然不能知足业务上复杂多变的需求,那么就自定义Function接口吧this
@FunctionalInterface static interface ThiConsumer<T,U,W>{ void accept(T t, U u, W w); default ThiConsumer<T,U,W> andThen(ThiConsumer<? super T,? super U,? super W> consumer){ return (t, u, w)->{ accept(t, u, w); consumer.accept(t, u, w); }; } }
自此,Function接口介绍完毕。code
接口介绍:htm
/** * Represents a predicate (boolean-valued function) of one argument. * * <p>This is a <a href="package-summary.html">functional interface</a> * whose functional method is {@link #test(Object)}. * * @param <T> the type of the input to the predicate * * @since 1.8 */ @FunctionalInterface public interface Predicate<T> {
Predicate是个断言式接口其参数是<T,boolean>,也就是给一个参数T,返回boolean类型的结果。跟Function同样,Predicate的具体实现也是根据传入的lambda表达式来决定的。接口
源码再也不具体分析,主要有 test/and/or/negate方法,以及一个静态方法isEqual,具体使用实例以下:
private static void testPredict() { int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; List<Integer> list = new ArrayList<>(); for (int i : numbers) { list.add(i); } // 三个判断 Predicate<Integer> p1 = i -> i > 5; Predicate<Integer> p2 = i -> i < 20; Predicate<Integer> p3 = i -> i % 2 == 0; List test = list.stream() .filter(p1 .and(p2) // .and(Predicate.isEqual(8)) .and(p3)) .collect(Collectors.toList()); System.out.println(test.toString()); //print:[6, 8, 10, 12, 14] }
接口介绍
/** * Represents a supplier of results. * * <p>There is no requirement that a new or distinct result be returned each * time the supplier is invoked. * * <p>This is a <a href="package-summary.html">functional interface</a> * whose functional method is {@link #get()}. * * @param <T> the type of results supplied by this supplier * * @since 1.8 */ @FunctionalInterface public interface Supplier<T>
使用实例:
Supplier supplier = "Hello"::toLowerCase; System.out.println(supplier);
接口介绍
/** * Represents an operation that accepts a single input argument and returns no * result. Unlike most other functional interfaces, {@code Consumer} is expected * to operate via side-effects. * * <p>This is a <a href="package-summary.html">functional interface</a> * whose functional method is {@link #accept(Object)}. * * @param <T> the type of the input to the operation * * @since 1.8 */ @FunctionalInterface public interface Consumer<T> {
实际使用
NameInfo info = new NameInfo("abc", 123); Consumer<NameInfo> consumer = t -> { String infoString = t.name + t.age; System.out.println("consumer process:" + infoString); }; consumer.accept(info);
总结: 本文主要介绍Java8的接口式编程,以及jdk中提供的四种函数接口(FunctionalInterface)。Predict/Supplier/Consumer实际上是Function的一种变形,因此没有详细介绍。 疑问: FunctionalInterface注解是如何和lamada表达式联系在一块儿,函数接口在编译时又是如何处理的?后面再了解下