Java8-5-函数式接口进阶与默认方法详解
上一篇咱们快速的借助示例演示了stream api的简单应用,体会到了使用stream api对集合处理的便捷和其与函数式接口密不可分的关系,因此为了更高效的使用stream api,有必要更熟练的掌握函数式接口。Java8中内置了大量的函数式接口,接下来咱们选择一些比较经常使用的一块儿学习下。html
Function接口
在以前的文章中,咱们简单介绍过Function接口中apply方法的应用,除了apply这个抽象方法,Function接口中还内置了两个比较经常使用的默认方法(接口中增长的有具体实现的方法,扩展了接口功能,子类默认会继承该实现),看下Function接口源码segmentfault
/** * 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 */ @FunctionalInterface public interface Function<T, R> { R apply(T t); /** * @return a composed function that first applies the {@code before} * function and then applies this function */ default <V> Function<V, R> compose(Function<? super V, ? extends T> before) { Objects.requireNonNull(before); return (V v) -> apply(before.apply(v)); } /** * @return a composed function that first applies this function and then * applies the {@code after} function */ default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); } /** * 省略 */ }
Function接口定义中有两个泛型,按着接口文档说明第一个泛型是输入类型,第二泛型是结果类型。
compose方法接收一个Function参数before,该方法说明是返回一个组合的函数,首先会应用before,而后应用当前对象,换句话说就是先执行before对象的apply,再执行当前对象的apply,将两个执行逻辑串起来。
andThen方法接收一个Function参数after,与compose方法相反,它是先执行当前对象的apply方法,再执行after对象的方法。看一个应用示例api
public class FunctionTest { public static void main(String[] args) { FunctionTest functionTest = new FunctionTest(); System.out.println(functionTest.compute1(5,i -> i * 2,i -> i * i));//50 System.out.println(functionTest.compute2(5,i -> i * 2,i -> i * i));//100 } public int compute1(int i, Function<Integer,Integer> after,Function<Integer,Integer> before){ return after.compose(before).apply(i); } public int compute2(int i, Function<Integer,Integer> before,Function<Integer,Integer> after){ return before.andThen(after).apply(i); } }
定义了compute1和compute2两个方法,compute1方法第一个参数是要计算的数据,第二个参数是后执行的函数,第一个是先执行的函数,由于输入输出都是数字类型,因此泛型都指定为Integer类型,经过after.compose(before);将两个函数串联起来而后执行组合后的Funtion方法apply(i)。当调用compute1(5,i -> i 2,i -> i i)时,先平方再乘以2因此结果是50。而compute2方法对两个Function的调用正好相反,因此结果是100。数组
BiFunction接口
接下来继续看下另外一个很经常使用的函数式接口BiFunctionapp
/** * This is the two-arity specialization of {@link Function}. * @param <T> the type of the first argument to the function * @param <U> the type of the second argument to the function * @param <R> the type of the result of the function * * @see Function * @since 1.8 */ @FunctionalInterface public interface BiFunction<T, U, R> { /** * Applies this function to the given arguments. * * @param t the first function argument * @param u the second function argument * @return the function result */ R apply(T t, U u); /** * Returns a composed function that first applies this function to * its input, and then applies the {@code after} function to the result. * If evaluation of either function throws an exception, it is relayed to * the caller of the composed function. * * @param <V> the type of output of the {@code after} function, and of the * composed function * @param after the function to apply after this function is applied * @return a composed function that first applies this function and then * applies the {@code after} function * @throws NullPointerException if after is null */ default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t, U u) -> after.apply(apply(t, u)); } }
实际上就是能够有两个参数的Function,一样前两个泛型表明着入参的类型,第三个表明结果类型。函数
public class BiFunctionTest { public static void main(String[] args) { BiFunctionTest2 biFunctionTest2 = new BiFunctionTest2(); System.out.println(biFunctionTest2.compute(4,5,(a,b) -> a * b,a -> a * 2)); } public int compute(int a, int b, BiFunction<Integer,Integer,Integer> biFunction, Function<Integer,Integer> function){ return biFunction.andThen(function).apply(a,b); } }
看下compute方法,前两个参数是待计算数据,第三个是一个BiFunction,由于入参和结果都是数组因此三个泛型都定义为Integer。最后一个参数是Function。计算逻辑是先执行BiFunction而后将结果传给Funciton在计算最后返回结果,因此使用了andThen方法。咱们想一下,BiFunction的andThen方法为何接收的是Function类型的参数而不是BiFunction,答案很简单,由于BiFunction的apply方法接收两个参数,可是任何一个方法不可能有两个返回值,因此也没办法放在BiFunction前面执行,这也是为何BiFunction没有compose方法的缘由。学习
下一篇ui