本文继续上一篇的内容
在Java中,函数可以表现为一个普通的方法、一个lambda表达式,又或者方法引用,甚至是匿名类。本文不会介绍匿名类这种形式。
方法
Java中的方法,Java使用方法这一概念来表示我们称之为函数的东西。一个方法是函数式的,只要它满足纯函数的额要求(注:上一章有详细介绍)。但是在Java中,一个方法不可能被当成参数传递给另一个方法,你也就无法复合这些方法。Java的方法只属于它在的类。
函数的复合:
java函数式编程的好处、就和高中数学所学的那样,程序里的函数也可以相互复合。这里有两个函数:
f (x) = x+1;
g(x) = x*2;
函数f和g复合后即为f(g(x)) = f(x*2)=(x*2)+1;我们可以为新函数起个名,即h(x)= (x*2)+1;
将参数3应用于这个复合函数可得 f(g(3)) =6+1 =7;
JAVA函数式编程?所幸的是,Java为我们提供了函数式接口和lambda表达式来模拟这一过程。使用我们上一章定义的Function接口,我们可以表示上面的例子:
Function f = i -> i + 1;
Function g = i -> i * 2;
Function h = f.compose(g);
int result = h.apply(3); //“7”
java构造函数初始化、我们也可以使用andThen方法,f.andThen(g)代表的含义是将f函数得到的结果作为参数应用到函数g。
这两个方法定义如下:
public interface Function {
U apply(T t);
default Function compose(Function f) {
java getint(),return x -> apply(f.apply(x));
}
default Function andThen(Function f) {
return x -> f.apply(apply(x));
}
java函数调用?}
这是一个函数式接口,因为它只有一个抽象方法,接口中存在的默认方法不会影响到它的定义。
区别如图所示:
函数复合
我们可以看出这两个方法存在冗余,因为g.compose(f)与f.andThen(g)完全等价。
注:在使用Java官方提供的函数式接口时,你会遇到名为@FunctionalInterface的注解,
js函数式编程。@FunctionalInterface
public interface Function {
……//仅含有一个抽象方法
}
这个标识性注解告诉编译器,这个类将被设计成函数式接口,有且仅有一个抽象方法。如果你用了这个注解但接口却定义了多个抽象方法
java编程思想。@FunctionalInterface
public interface Function {
U apply(T t);
void f();
}
java,这时编译器会提示你:
Invalid '@FunctionalInterface' annotation; Function is not a functional interface。
但这个注解不是必须的,你也可以不使用它,只要你的接口符合函数式接口的规范。然而,在编写函数式接口时使用它仍是一个好习惯。
方法引用
如果你觉得lambda难懂或麻烦,在某些情况下,可以用方法引用这种快捷写法代替。
请看下面的例子:
函数?实例方法引用和类型的实例方法引用可能有点难以理解,实例方法引用,就是调用已经存在的实例的方法,这个对象实例是lambda表达式外部的实例。而类型的实例方法要求Lambda 参数列表的第一个参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数。
而对于构造函数的引用,根据构造函数参数的不同,可分为:
假设这有个类User{
……//
}
java函数式编程有必要吗、无参
Supplier supplier= User::new;
User user = supplier.get();
一个参数(假设参数类型为T):
Function function = User::new;
函数柯里化的意义、User user = function.apply(t);
两个参数(假设类型分别为T,U):
我们定义一个函数式接口
interface BiFunction(T,U,R){
R apply(T t,U u);
Java函数式编程,}
BiFunction biFunction = User::new;
User user = biFunction.app(t,u);
其他的以此类推。我们需要有与构造方法匹配的函数式接口。
高阶函数及相关特性
java响应式编程?如果一个函数(Java里称作方法)有多个参数,我们能永远将它看作只有一个参数的函数,而我们所做的,就是使用元组。函数有两个参数,可以说它有一个二元组参数,三个参数、四个参数亦是如此。例如,在scala里,我们可以简单定义一个元组,val t3= (1,2.0,”3”) 。它可以通过t3._1访问第一个元素,t3._2访问第二个元素,以此类推。
遗憾的是,Java并不支持元组类型,好在我们可以用类和泛型自定义自己的元组使用。例如二元组Tuple2、三元组Tuple3等。
下面是一个元组定义的例子,这是一个二元元组。
public class Tuple {
public final T _1;
public final U _2;
public Tuple(T _1, U _2) {
super();
this._1 = _1;
this._2 = _2;
}
@Override
public String toString() {
return "Tuple = [" + _1 + "][" + _2 + "]";
}
}
柯里化
在上一章中,我曾介绍过一个函数:
public static Function f(String args,Function> g){
return g.apply(args);
}
我说过,这和函数的柯里化有关,接下来我将想你介绍何为柯里化和部分施用。这两个概念极易混肴。某种意义上说,他们产生的效果,得到的结果是一样的,以至于在Groovy语言里,把他们统称为了柯里化。
简单来说,柯里化就是把一个多参函数转化为一串串单参函数的过程,参数可以一个接一个应用,除了最后一个参数外,其他参数都会产生一个全新的函数。
例如对函数F(X,Y,Z),柯里化后将会得到F(X)(Y)(Z)。你可决定到底对多少个参数实施变换。而部分使用就是提前带入一部分具体的参数值,部分求解后得到一个参数较少的函数。
例如对函数F(X,Y,Z),我们提前施用X的值,将会得到F(Y,Z)。
对于函数Function>来说,它会接受一个String类型的参数,并返回一个String->Integer类型的参数 。
例如:
f("abs",s->x->s.length()+x.length()).apply("abcds")
这个函数执行的结果为8,它只是将两个字符串的长度相加而已。实际上具体多少参数不做限制,只是Java里写起函数类型太麻烦。在Scala里,你可以这样表示:
f (“abs”) (“abcds”)。
对于上面这种可以接受函数作为参数,也可以将函数作为结果返回的函数,我们称之为高阶函数。
下一篇中,我将通过定义一个列表List,这个列表更加符合函数式的数据结构。同时通过这个列表向大家介绍函数式编程的三板斧,filter,map,fold.即过滤,映射,折叠(部分语言称为reduce归约)。
版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。
工作时间:8:00-18:00
客服电话
电子邮件
admin@qq.com
扫码二维码
获取最新动态