欢迎浏览我的博客 获取更多精彩文章

https://boyn.top

Java函数式编程(一)–Function的使用

在函数式编程中,我们用的最多的往往是Function接口.通常来说,我们很少会直接使用这个接口,但是在Java的函数式编程中,许多组件都会与这个接口有关.需要注意的是,很多人会混淆Java8中新增的Stream API与函数式编程的概念,事实上,Stream API是一种为了实现自动化并行的惰性求值的解决方法,与函数式没有太大关系,但是其与函数式编程结合会很好用.

回到正题,Function是函数式编程的基石之一,其与函数柯里化,高阶函数,复合函数等等概念的实现有关.我们现在看看其接口的组成

Function Interface

单一函数声明

public interface Function<T,R>{R apply(T t);
}

为了说明Function的核心概念,我们省略了两个实现复合函数的方法(compose和andthen,稍后会说到)

毫无疑问,这是一个函数式的接口,所以完全可以使用lambda表达式来实现这个接口,我们来看一下一些简单的应用

        Function<Integer,Integer> triangle = arg -> arg*3;Function<Integer,Integer> square = arg -> arg*arg;int result1 = triangle.apply(1); //result1: 3int result2 = square.apply(1);//result2: 1

复合函数声明

当然,我们不只是希望能够使用单一的函数,我们想要使用复合函数来达到更多的目的.复合函数可以理解成是基本Function接口的二元操作,我们可以用一个方法,来达到这个效果,那就是compose方法(andthen函数与compose其实是一对互为冗余的方法,他们实现的目的是一样的,只是角度不一样,所以在这里只说一下compose)

default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {Objects.requireNonNull(before);return (V v) -> apply(before.apply(v));}

这个是在Function接口中实现的默认方法compose,对于单个参数的情况,与我们在数学公式中常见的

g(x) = x * 2,f(x) = x+x, f(g(x)) = x * 2+x * 2的效果是一样的,所以我们来看一个简单的使用

Function<Integer,Integer> area1 = triangle.compose(square);
Function<Integer,Integer> area2 = square.compose(triangle);
area1.apply(1);//tri(squ(1))
area2.apply(1);//squ(tri(1))

多参函数声明

在Function接口中,我们只有一个输入参数和一个输出,那么,如果要定义一个多参的函数,要怎么做呢?

我们可以从两个角度来看,第一个角度,我们可以将输入参数看作是一个元组,如果有两个输入参数,那么输入就是一个二元组,以此类推.第二个角度,我们可以一个接着一个地应用不同的参数,除了最后一个参数外,每一个参数应用后都会返回一个新的函数.

我们称第二个方法为函数的柯里化,这是一个高级函数的特性,我们来看一下使用的方法

Function<Integer, Function<Integer, Integer>> add = x -> (y -> (x + y));
add.apply(3).apply(5);//result: 8

在第一行,我们定义了一个输入为(一个输入为一个整数,输出为一个整数的Function),输出为一个整数的Function.并在第二行用apply方法进行传参.那么,如果一个方法有3个参数,又要怎么写呢

Function<Integer, Function<Integer, Function<Integer, Integer>>> axPlusb = a -> (x -> (b -> (a * x + b)));
int y = axPlusb.apply(2).apply(3).apply(4);

我们定义了一个y=ax+b的函数.

但是问题也接踵而至,在代码中,我们发现这样写太过于繁杂了,并且很长.不过幸好,在柯里化的函数中,通常只有两个值到四个值左右,所以我们可以定义各自的接口.

interface BiaryOperator extends Function<Integer,Function<Integer,Integer>>{} //
BiaryOperator add = x -> (y -> (x + y));

高阶函数声明

我们在复合函数中,使用了一个compose方法来接受两个函数并返回一个复合了之后的函数.那么,如果我们可以用一个函数,做到同样的事情,我们就称这个函数为高阶函数

首先,我们要确定参数,他的输入是两个函数,输出是一个函数.根据上面所说的柯里化,我们可以分别对其进行类似多参函数的声明.有如下声明

Function<Function<Integer, Integer>, Function<Function<Integer, Integer>, Function<Integer, Integer>>> compose = x -> y -> z -> (x.apply(y.apply(z)));

可以在一行内写完.

自动柯里化

自动柯里化在函数式编程中是一个很重要的概念,自动柯里化与部分应用函数紧密地结合着.柯里化包括了把接受元组的函数替换为可以部分应用各个参数的函数.我们在使用完全应用函数前,需要对元函数进行柯里化来将其转化为部分应用函数.例如,一个接受三个参数的函数可以被柯里化成一个生成单参函数的二元函数.

//假设我们有一个双参的柯里化函数,我们需要接受它的第一个参数来将其转化为部分应用函数
<A,B,C> Function<B,C> partialA(A a, Function<A,Function<B,C>> f){return f.apply(a);
}
//再假设我们有一个双参的柯里化函数,我们需要接受它的第二个参数来将其转化为部分应用函数
<A,B,C> Function<A,C> partialB(B b,Function<A,Function<B,C>> f){return a->f.apply(a).apply(b);
}

下面我们来看一些柯里化应用的例子.其实,我们要实现柯里化,最重要的一点,就是要跟着类型走,只要定义好了方法的签名,那么实现柯里化就是一件很简单的事情了

首先来看一下将一个多参函数柯里化的例子

//将以下函数转换成一个柯里化函数
<A,B,C,D> String func(A a,B b,C c,D d){return String.format("%s %s %s %s",a,b,c,d);
}
//在转换前,我们只需要知道多层输入的类型和输出,那么就可以简单地写出方法的签名了
<A,B,C,D> Function<A,Function<B,Function<C,Function<D,String>>>> func()
//然后就是实现了,实现起来十分简单,就是单输入柯里化的嵌套
{return a->b->c->d-> String.format("%s %s %s %s",a,b,c,d);
}
//应用也很简单
String string  = func().apply("A").apply("B").apply("C").apply("D");

再来看一个交换部分应用参数的例子.在应用函数式的过程中,我们可能需要交换apply的顺序,这个时候就要牵涉到交换柯里化顺序了

public static <T,U,V> Function(U,Function(T,V)) reverseArgs(Function<T,Function<U,V>> f){return u->t->f.apply(t).apply(u);
}
//仍然是那句话,我们需要跟着参数走,函数f apply的顺序是不会变的,我们要改变的是柯里化传值的顺序

完整的Function接口函数

综合上面所说的,我们可以写出一个完整的,包含复合函数生成的Function接口

import java.util.Objects;/*** @author Boyn* @date 2019/8/14* @description 这个类是函数式编程的基础,实现这个接口可以表示一个单输入单输出的函数* 这个接口还包含了许多复合函数与柯里化的实现*/
/*频繁往外读取内容的,适合用上界Extends。
经常往里插入的,适合用下界Super。*/
@FunctionalInterface
public interface Function<T,U> {U apply(T arg);/*** 生成复合函数*/default <R> Function<R,U> compose(Function<? super R,? extends T> before){Objects.requireNonNull(before);return (R r)-> apply(before.apply(r));}/*** 生成复合函数的另一种表达*/default <R> Function<T,R> andThen(Function<? super U,? extends R> after){Objects.requireNonNull(after);return (T t) -> after.apply(this.apply(t));}/*** 实现一个恒等函数*/static <T> Function<T,T> identity(){return t->t;}/*** 生成复合函数的静态方法*/static <T,U,V> Function<V,U> compose(Function<T,U> f,Function<V,T> g){return (V v)->f.apply(g.apply(v));}/*** 生成复合函数的静态方法*/static <T,U,V> Function<T,V> andThen(Function<T,U> f,Function<U,V> g){return (T t)->g.apply(f.apply(t));}}

Java函数式编程(一)–Function的使用相关推荐

  1. java函数式编程接口Function<T,R>实现数据转换

    java.util.function.Function<T,R>接口用来根据一个类型的数据得到另一个类型的数据, 前者称为前置条件,后者称为后置条件. 1. apply方法应用 Funct ...

  2. Java 函数式编程和 lambda 表达式

    为什么要使用函数式编程 函数式编程更多时候是一种编程的思维方式,是种方法论.函数式与命令式编程的区别主要在于:函数式编程是告诉代码你要做什么,而命令式编程则是告诉代码要怎么做.说白了,函数式编程是基于 ...

  3. java 函数式编程 示例_功能Java示例 第8部分–更多纯函数

    java 函数式编程 示例 这是第8部分,该系列的最后一部分称为"示例功能Java". 我在本系列的每个部分中开发的示例是某种"提要处理程序",用于处理文档. ...

  4. java 函数式编程_Java函数式编程:Javaslang入门

    java 函数式编程 Java是一门古老的语言,并且该领域中有很多新手在他们自己的领域(JVM)上挑战Java. 但是Java 8到来并带来了一些有趣的功能. 这些有趣的功能使编写新的惊人框架(例如S ...

  5. Java函数式编程整理

    2019独角兽企业重金招聘Python工程师标准>>> Java函数式编程的第一个作用是可以将匿名类改写成函数式表达式,由系统自动判断类型 我们先定义一个接口 public inte ...

  6. 【CSDN软件工程师能力认证学习精选】 Java8新特性学习-函数式编程(Stream/Function/Optional/Consumer)

    CSDN软件工程师能力认证是由CSDN制定并推出的一个能力认证标准,宗旨是让一流的技术人才凭真才实学进大厂拿高薪,同时为企业节约大量招聘与培养成本,使命是提升高校大学生的技术能力,为行业提供人才储备, ...

  7. 0202年了,还没有用上Java函数式编程!!!——Lambda表达式

    0202年了,还没有用上Java函数式编程!!!--Lambda表达式 函数式编程是什么 命令式编程(Imperative) 声明式编程(Declarative) 函数式编程(Functional) ...

  8. Java 函数式编程

    Java 函数式编程 一.Lambda表达式 1.1 函数式编程思想概述 在数学中,函数就是有输入量.输出量的一套计算方案,也就是"拿数据做操作" 面向对象思想强调"必须 ...

  9. Java函数式编程随想

    java函数式编程的类主要定义在java.util.function包下.快速浏览了下该包下的一些类和接口.读者要想看懂function相关的源码,也需要对lambda表达式和泛型有一定的了解.本文只 ...

  10. Java函数式编程知识分享!

    Java是一种计算机编程语言,可用于编写桌面应用程序.Web应用程序.分布式系统和嵌入式系统应用程序等,是IT开发行业中最受欢迎的编程语言之一.想要学好Java必须要一步一个脚印打好基础.积攒实战经验 ...

最新文章

  1. 第五节 RabbitMQ在C#端的应用-消息收发
  2. 第7章 jQuery中的事件与动画
  3. js数组遍历、对象遍历、字符串遍历
  4. 中国-中东欧国家特色农产品 云上国际农民丰收节贸易会
  5. Scala算术运算符的一览图
  6. GNU ARM汇编伪操作(Directives) 命令集
  7. Centos7.5 VMtools的安装与卸载
  8. 微信web开发者工具初次安装无法打开的几种解决办法
  9. 惯性积计算实例_关于材料力学中惯性矩的认识00
  10. synchronized关键字的4种用法
  11. 安装程序总是提示重启计算机,技巧|安装西门子软件反复提示重启电脑的解决方法...
  12. QML_虚拟键盘使用
  13. MyBatis第N+1种分页方式,全新的MyBatis分页
  14. Vue # Avoid mutating a prop directly since the value will be overwritten wheneve
  15. python爬取大学生就业分析专科和本科的信息https://edu.jobui.com/major/(上)JSON的存储
  16. 找完数——完数的使用
  17. 在Google 上搜书的方法
  18. C#数字金额转人民币大写金额的实现
  19. 【python】choice函数
  20. DS_SpanningTree

热门文章

  1. 文华wh6如何修改服务器,文华财经 软件特色功能介绍修改
  2. unity AI Planner 人工智能简介
  3. 怎样使用Google chrome播放 .swf 文件
  4. LinuxCNC的能做什么
  5. Java 算法 - 递归算法思想
  6. 毒(得物)APP历史购买数据抓取
  7. php源码 备课系统,电子教案管理系统2012版 V3.2
  8. 射频IC理论知识/参考书
  9. SecureCRT的下载与使用
  10. 为了在 Windows 11 上启用 IE ,我撸了个修复工具