在过去的编程中,我们常用命令式编程。在 Jdk8 为我们提供了一种全新的编程思维 - 函数式编程,那么这种编程方式究竟有什么不同呢?
再命令式编程中,我们习惯用对象引用来指定确定对象。可以看出我们编程的重点在于对象本身,我们通过调用函数来处理对象,通过这种方式来达到自己的目的。 而在函数式编程中,我们有了方法引用这个概念,引用不仅仅可以只想以个对象还可以指向一个函数,这就使我们的关注点从对象转换到了变化本身。
函数式接口
函数式编程的根本是可以通过方法引用来指向一个具体函数,jdk 提供了一些函数式接口来表示一个函数对象。常用接口如下
接口 | 描述 |
---|---|
Function | 接受一个输入 T 类型参数,返回一个 R 类型结果。 |
Consumer | 接受一个输入 T 类型参数并且无返回的操作 |
Predicate | 接受一个输入 T 类型参数返回一个 boolean 类型结果 |
Supplier | 无参数返回一个 T 类型结果 |
BiFunction | 接受 T,U 两个类型输入参数,返回一个 R 类型结果。 |
BiConsumer | 接受两个类型参数并且无返回的操作 |
BiPredicate | 接受两个类型参数返回一个 boolean 类型结果 |
获取方法对象 (通过::关键字)
了解了函数式接口的类型,那么如何使用这些接口?或者说如何获取一个函数对象?jdk 为我们提供了 2 个关键字::和->,首先我们来介绍::,他用来获取一个类中的具体方法,使用方法如下:
class Person {
static{
//声明一个Consumer对象,指向Person的静态方法。
Consumer<Long> consumer = Person::methodStatic;
//获取一个对象的非静态方法。
consumer = new Person()::method;
//输入参数执行对应函数。
consumer.accept(new Long(1));
}
public void method(Long a) {
}
//静态方法
public static void methodStatic(Long a) {
}
}
获取方法对象 (通过 Lambda 表达式)
下面我们来了解一下->关键字也就是著名的 Lambda 表达式。
lambda 表达式是以 (参数 A,参数 B)->{ 代码块 }的形式来表达一个函数。比如
//这里省略了{},也可以写为function=(t)->{ return t+1; }
Function<Long,Long> function=(t)-> t+1;
Consumer<Long> consumer=(t)->{t=t+1;};
Predicate<Long> predicate=(t)-> t==1?true:false;
Supplier<Long> supplier=()->new Long(1);
自定义函数接口
JDK8 给我们提供了一个注解@FunctionalInterface这个注解背用于声明一个接口是函数接口并且对接口是否符合函数接口规范作出检测。 使用此注解的接口中有且仅能有一个抽象方法(不包括重写父类 Object 的基础方法),你的函数将会绑定到这个方法上用于执行, 比如 Consumer 的 accept() 方法,Predicate 的 test() 方法,Function 的 apply() 方法下面我们自定义一个接受三个参数没有返回值的函数接口。
@FunctionalInterface
interface CustomFunction<T,U,P>{
//唯一的抽象方法。
void doSomething(T t,U u,P p);
}
//然后我们使用这个接口得到结果控制台输出8
static {
CustomFunction<Long,Long,Long> customFunction=(a,b,c)->{System.out.println(a+b+c);};
customFunction.doSomething(new Long(2),new Long(2),new Long(4));
}
Lambda 表达式内部实现实际是在接口中生成一个内部类,所以同样在方法内部使用的外部变量也必须用 final 修饰。 而::方式也是再编译时生成一个 Lambda 表达式。从下方代码可以看出同样引用 peron 对象的 method 方法但指向的地址空间不同。
Person person=new Person();
Consumer<Long> consumer2=person::method; //Test$lambda@690
Consumer<Long> consumer2=person::method; //Test$lambda@691