Java8-5-函数式接口进阶与默认方法详解
上一篇我们快速的借助示例演示了stream api的简单应用,体会到了使用stream api对集合处理的便捷和其与函数式接口密不可分的关系,所以为了更高效的使用stream api,有必要更熟练的掌握函数式接口。Java8中内置了大量的函数式接口,接下来我们选择一些比较常用的一起学习下。

Function接口
在之前的文章中,我们简单介绍过Function接口中apply方法的应用,除了apply这个抽象方法,Function接口中还内置了两个比较常用的默认方法(接口中增加的有具体实现的方法,扩展了接口功能,子类默认会继承该实现),看下Function接口源码

/*** 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对象的方法。看一个应用示例

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));//50System.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接口
接下来继续看下另一个很常用的函数式接口BiFunction


/*** 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方法的原因。

下一篇

Java8-5-Function函数式接口进阶与默认方法详解相关推荐

  1. Java8中Function函数式接口详解及使用

    文章目录 1.函数式接口 1.1允许定义默认方法 1.2允许定义静态方法 1.3允许定义java.lang.Object的public方法 1.4已有函数式接口 2.Function函数 2.1Fun ...

  2. Java8新特性_接口中的默认方法

    默认方法由来猜想 1. Collection接口.Collections公共类.  同是操作集合,为啥要搞俩?没必要.在接口中搞一些默认实现,一个接口即搞定了. 2. Java8支持Lambda表达式 ...

  3. [享学Eureka] 三十一、DiscoveryClient透彻解析(八):接口方法和shutdown()方法详解

    成为一个成功者最重要的条件,就是每天精力充沛的努力工作,不虚掷光阴. –> 返回Netflix OSS套件专栏汇总 <– 代码下载地址:https://github.com/f641385 ...

  4. Java8新特性Optional、接口中的默认方法与静态方法

    Optional Optional 类(java.util.Optional) 是一个容器类,代表一个值存在或不存在,原来用 null 表示一个值不存在,现在 Optional 可以更好的表达这个概念 ...

  5. Function 函数式接口及应用

    Lambda表达式和函数式编程接口 Lambda表达式是整个Java 8体系中最让人期待的特性(Java 8 新特性终极指南),它允许我们將函数作为一个方法的参数传递到方法体中或者將一段代码作为数据, ...

  6. Java接口中的默认方法冲突

    在Java中,我们可以为其接口中定义的方法提供一个默认的实现.当然,这可能并没有很大的用处,不过,在某些情况下可能很有用!如果要为接口方法提供一个默认实现,必须要用 default关键字 修饰. 在为 ...

  7. JavaSE——面向对象进阶(封装、this、static、代码块、包、权限修饰符、main方法详解)

    第2节 面向对象进阶 一.封装与private 概述: 封装的意义在于保护或者防止代码(数据)被我们无意中破坏.保护成员属性,不让类以外的程序直接访问和修改. 封装原则: 隐藏对象的属性和实现细节,仅 ...

  8. [进阶] --- Python3 异步编程详解(史上最全篇)

    [进阶] - Python3 异步编程详解:https://blog.csdn.net/lu8000/article/details/45025987 参考:http://aosabook.org/e ...

  9. 静态路由和默认路由详解及配置方法️

    目录 一.路由详解 1.路由器工作原理: 2.路由表形成: 3.直连路由: 4.非直连路由: 二.静态路由 1.静态路由详解: 2.配置静态路由 三. 默认路由: 1.默认路由详解 2.配置默认路由方 ...

最新文章

  1. mysql图形化及命令行操作用户权限
  2. 不可思议!英伟达新技术训练NeRF模型最快只需5秒,代码已开源
  3. 号外:Mapinfo被Pitney Bowes公司收购
  4. Apriori算法实例
  5. windows下PXE+TFTP+HTTP自动安装ubuntu server
  6. Spring Boot版微信支付教程(视频 源码笔记)
  7. C语言结构体与联合体
  8. Windows优化大师的一点研究
  9. linux下线程绑定内核,多线程 – 无法将内核线程绑定到CPU
  10. python难学吗-Python入门很难吗? 为什么越来越多的人都学Python?
  11. 杭州哪里学python好_杭州哪里学python好
  12. 使用JavaParser进行java源码解析
  13. 12.卷1(套接字联网API)---IPv4与IPv6的互操作性
  14. Smarty下载和安装
  15. 服务器基础设置:服务器设置PXE启动,
  16. 使用计算机组成原理全加器设计,杭电计算机组成原理全加器设计实验1
  17. 百度LBS开放平台Android SDK产品使用
  18. Hadoop系列-MapReduce设计思想与原理机制(九)
  19. HTML5 video autoplay=autoplay 无法自动播放的问题
  20. 为什么我们对工作缺乏责任心

热门文章

  1. 对外合作对话国际农民丰收节贸易会 农业农村部谋定稳求进
  2. TCP 三次握手过程详解
  3. 最全解释P2P、P2C 、O2O 、B2C、B2B、 C2C的定义
  4. UVA 10803 Thunder Mountain
  5. vc编程中出现 fatal error C1010: 在查找预编译头时遇到意外的文件结尾。是否忘记了向源中添加“#include stdafx.h”?...
  6. javaScript 实现多选框全选/反选及批量删除
  7. 互联网医疗上市“大逃杀”
  8. 10个月产品演化之路-快速试错,快速反应,探索产品成功之道
  9. 微课堂 | 典典养车COO:暴力运营美学,典典养车如何一年内拿到500万用户(今晚8点开始)...
  10. 【pmcaff】重磅干货,必读的扁平化设计技巧