开宗明义
java8的一个新特性就是在java.util.function中提供了四个函数式编程接口,分别是Consumer、Supplier、Function、Predicate。
其中,
- consumer即消费接口,传入一个参数,并对其进行相应的操作(有点类似于lambda表达式);
- supplier即供给接口,可以传入数据,作为一个容器;
- function即方法接口,主要是用作数据类型之间的转换;
- predicate即判断接口,传入参数,而后返回判断的结果true/false;
接下来仔细瞅瞅这四种接口的源码以及怎么使用它们。
庖丁解牛
consumer
源码
Consumer接口的源码只有两个方法,一个方法用来接收入口参数,另外一个是为了实现流式操作:
@FunctionalInterface public interface Consumer<T> { /** *接收一个泛型入参 */ void accept(T t); /** * 是指在进行这个consumer之后,在将结果送进另外一个consumer, * 从而实现consumer的流式操作(一个接一个地进行) */ default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; } }
注:@FunctionalInterface注解即是表明它是一个函数接口,另外的supplier、function、predicate同样如此。
示例
实现Consumer接口可以有三种方式,看下面:
public static void main(String[] args) { //1:平平无奇:直接创建接口并重载 Consumer<String> consumer1 = new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } }; Stream<String> stream1 = Stream.of("spring", "summer", "autumn", "winter"); stream1.forEach(consumer1); System.out.println("********************"); //2:偶有起色: 使用Java8另外一个特性,方法引用 Consumer consumer2 = System.out::println; Stream<String> stream2 = Stream.of("spring", "summer", "autumn", "winter"); stream2.forEach(consumer2); System.out.println("********************"); //3:精彩绝伦,使用lambda表达式 Consumer<String> consumer3 = (s) -> System.out.println(s);//lambda表达式返回的就是一个Consumer接口 Stream<String> stream3 = Stream.of("spring", "summer", "autumn", "winter"); stream3.forEach(consumer3); } //改写自:https://cloud.tencent.com/developer/article/1488128
结果如下:
spring summer autumn winter ******************** spring summer autumn winter ******************** spring summer autumn winter
注:Stream只能用一次,无法reuse,违规则报错,因此在上述测试的时候建立了多个Stream对象;
注:方法引用和lambda表达式就是consumer的实现,所以不用显示调用accept。
另外,对于集合类的foreach,是因为那么都实现了iterable接口,并且itrable接口支持Consumer:
public interface Iterable<T> { //forEach方法传入的就是Consumer default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); } } }
Supplier
源码
Supplier可以简单的视为就是一个存放指定类型的容器,需要时再取出来:
@FunctionalInterface public interface Supplier<T> { /** * Gets a result. * * @return a result */ T get(); }
在Optional类的orElseGet、orElse等API就使用了类Supplier,其中orElseGet的源码如下:
Optional.orElseGet(Supplier<? extends T>)
示例
和上面的Consumer一样,Supplier也可以通过三种方式来使用:
public void test_Supplier() { //1: 直接新建一个Supplier接口 Supplier<Integer> supplier = new Supplier<Integer>() { @Override public Integer get() { //返回一个随机值 return new Random().nextInt(); } }; System.out.println(supplier.get()); System.out.println("********************"); //2: 使用方法引用 Supplier<Double> supplier2 = Math::random; System.out.println(supplier2.get()); System.out.println("********************"); //3: 使用lambda表达式 supplier = () -> new Random().nextInt(); System.out.println(supplier.get()); } //改写自:https://cloud.tencent.com/developer/article/1488128
结果如下:
-1704173567 ******************** 0.7995174190529915 ******************** 2009273688 Process finished with exit code 0
可知,Suppiler就是一个用来获取对应类型返回值的函数接口,返回值可以通过传入的参数来设定。
Function
源码
Function的抽象方法只有一个apply,即对传入的参数进行处理并返回,其他的都是辅助方法:
@FunctionalInterface public interface Function<T, R> { /** * 抽象方法: 对一个数据类型T加工得到另一个数据类型R */ R apply(T t); /** * 组合函数,调用当前function之前调用 */ default <V> java.util.function.Function<V, R> compose(java.util .function.Function<? super V, ? extends T> before) { Objects.requireNonNull(before); return (V v) -> apply(before.apply(v)); } /** * 组合函数,调用当前function之后调用 */ default <V> java.util.function.Function<T, V> andThen(java.util .function.Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); } /** * 静态方法,返回与原函数参数一致的结果。x=y */ static <T> java.util.function.Function<T, T> identity() { return t -> t; } }
示例
Function接口的示例可以通过这个例子来一窥究竟:
public static void main(String[] args) { applyTest(); andThenTest(); composeTest(); test(); } //1、apply 示例 private static void applyTest() { //示例1:利用lambda方式实现一个funciton,将String转换为Integer Function<String, Integer> function = x -> Integer.parseInt(x); Integer a = function.apply("100"); System.out.println(a.getClass()); } //2、andThen 示例——实现一个函数 y=10x + 10; private static void andThenTest() { //先执行 10 * x Function<Integer, Integer> function2 = x -> 10 * x; //通过andThen在执行 这里的x就等于上面的10 * x的值 function2 = function2.andThen(x -> x + 10); System.out.println(function2.apply(2)); } //3、compose 示例-实现一个函数 y=(10+x)2 private static void composeTest() { Function<Integer, Integer> function3 = x -> x * 2; //先执行 x+10 在执行(x+10)*2顺序与上面相反 function3 = function3.compose(x -> x + 10); System.out.println(function3.apply(3)); } //4、综合示例 //使用compose()、andThen()实现一个函数 y=(10+x)*2+10; private static void test() { //真正执行的第二步 Function<Integer, Integer> function4 = x -> x * 2; //真正执行的第一步 function4 = function4.compose(x -> x + 10); //真正执行的第三步 function4 = function4.andThen(x -> x + 10); System.out.println(function4.apply(3)); }
先自己想一想结果,再往下看!!
输出结果为:
class java.lang.Integer 30 26 36 Process finished with exit code 0
除了上面使用的 Function 接口,还可以使用下面这些 Function 接口。 IntFunction 、DoubleFunction 、LongFunction 、ToIntFunction 、ToDoubleFunction 、DoubleToIntFunction 等等,使用方法和上面一样。
Function 接口实现 apply 方法来做转换。
Predicate
源码
Predicate的源码如下,该方法的辅助方法较多:
public interface Predicate<T> { /** * 判断参数T是否满足要求,可以理解为 条件A */ boolean test(T t); /** * 调用当前Predicate的test方法之后再去调用other的test方法,相当于进行两次判断 * 可理解为 条件A && 条件B */ default Predicate<T> and(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) && other.test(t); } /** * 对当前判断进行"!"操作,即取非操作,可理解为 ! 条件A */ default Predicate<T> negate() { return (t) -> !test(t); } /** * 对当前判断进行"||"操作,即取或操作,可以理解为 条件A ||条件B */ default Predicate<T> or(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) || other.test(t); } /** * 对当前操作进行"="操作,即取等操作,可以理解为 A == B */ static <T> Predicate<T> isEqual(Object targetRef) { return (null == targetRef) ? Objects::isNull : object -> targetRef.equals(object); } } //源码来自:https://www.cnblogs.com/qdhxhz/p/12050701.html
示例
这里给出两种实现Predicate接口的方式——直接创建与lambda表达式:
public class TestFunction { public static void main(String[] args) { //1:直接创建Predicate接口 Predicate<Integer> predicate = new Predicate<Integer>() { @Override public boolean test(Integer integer) { if(integer > 10){ return true; } return false; } }; System.out.println(predicate.test(6)); System.out.println("********************"); //2: 通过lambda表达式, predicate = (t) -> t > 5; System.out.println(predicate.test(1)); System.out.println("********************"); } } //改写自:https://cloud.tencent.com/developer/article/1488128
结果为:
false ******************** false ******************** Process finished with exit code 0
总结
看了以上四个函数式接口的源码、示例,也许会有点疑惑——这些东西到底有啥用?感觉用处不大啊!
回答:为了进行函数式编程。关于函数式编程的好处和理念之后再细说,详情可参考。
参考资料
https://cloud.tencent.com/developer/article/1488128