赞
踩
使用Consumer作为示例,它是一个函数式接口,包含一个抽象方法accept,这个方法只有输入而无输出也就是说这个方法无返回值。
现在我们要定义一个Consumer接口的实例化对象,传统的方式是这样定义的:
public static void main(String[] args) {
//JDK1.8版本之前的做法
Consumer<Integer> con = new Consumer<Integer>() {
@Override
public void accept(Integer t) {
System.out.println(t);
}
};
//调用方法
con.accept(3);
}
这里可以打印出3.
上面是JDK1.8以前的做法,在1.8以后引入函数式的编程可以这样写:
public static void main(String[] args) { // 1. Consumer只有一个入参,没有出参 // 第一种写法(有且只有一个入参) Consumer<Integer> con = (param) -> { System.out.println(param); }; // 第二种写法 Consumer<Integer> con1 = (param) -> System.out.println(param); // 第三种写法 Consumer<Integer> con2 = System.out::print; Consumer<Integer> con3 = (param) -> { System.out.println(param * param); }; Consumer<Integer> con4 = (param) -> { System.out.println(param + param + 1); }; // 调用 con.accept(1); con1.accept(2); con2.accept(3); }
上面的con、con1、con2这个Consumer对象的引用照样可以打印出3.
::
关键字来访问类的构造方法,对象方法,静态方法。好了,到这一步就可以感受到函数式编程的强大能力。
通过最后一段代码,我们可以简单的理解函数式编程,Consumer接口直接就可以当成一个函数了,这个函数接收一个输入参数,然后针对这个输入进行处理;当然其本质上仍旧是一个对象,但我们已经省去了诸如老方式中的对象定义过程,直接使用一段代码来给函数式接口对象赋值。
而且最为关键的是,这个函数式对象因为本质上仍旧是一个对象,因此可以做为其它方法的参数或者返回值,可以与原有的代码实现无缝集成!
常用的接口有:
java.util.function.Consumer;
java.util.function.Function;
java.util.function.Predicate;
Consumer是一个函数式编程接口; 顾名思义,Consumer的意思就是消费,即针对某个东西我们来使用它,因此它包含有一个有输入而无输出(无返回值)的accept接口方法;
除accept方法,它还包含有andThen这个方法;
JDK源码定义如下:
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
andThen这个方法是作用是:指定在调用当前Consumer后是否还要调用其它的Consumer;
public static void main(String[] args) { //定义第一个Consumer Consumer<Integer> consumer1 = (param) -> { System.out.println(param); }; //定义第二个Consumer Consumer<Integer> consumer2 = (param) -> { System.out.println(param * param); }; //consumer1可以连续的调用自己 consumer1.andThen(consumer1).andThen(consumer1).accept(3); //打印出 3 3 3 //consumer1可以调用自己后调用consumer2 consumer1.andThen(consumer1).andThen(consumer2).accept(3); //打印出3 3 9 }
注意:当一个Consumer接口调用另外一个Consumer对象时两个Counsumer对象的泛型必须一致。
Function也是一个函数式编程接口;它代表的含义是“函数”,它是个接受一个参数并生成结果的函数,而函数经常是有输入输出的,因此它含有一个apply方法,包含一个输入与一个输出;
除apply方法外,它还有compose与andThen及indentity三个方法,其使用见下述示例;
apply的用法:
public static void main(String[] args) {
Function<Integer, Integer> fun = res -> res + 1;
Integer i = fun.apply(2);
System.out.println(i);
}
上面打印出2。
Function编程接口有两个泛型Function<T, R> T表示:函数的输入类型,R表示:函数的输出类型。
compose的用法:
JDK源码定义:
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
public static void main(String[] args) {
Function<Integer, Integer> fun = res -> res + 1;
Function<Integer, Integer> fun1 = res -> res * 10;
Integer i = (Integer) fun.compose(fun1).apply(2);
System.out.println(i);
}
上面打印出21;
上面表示了 fun1 接收到 2 后先计算,然后将 fun1 计算的结果再交给 fun 再计算。
andThen方法的用法:
JDK源码定义:
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
public static void main(String[] args) {
Function<Integer, Integer> fun = res -> res + 1;
Function<Integer, Integer> fun1 = res -> res * 10;
Integer i = (Integer) fun.andThen(fun1).apply(3);
System.out.println(i);
}
上面打印出40
上面表示了 fun 先计算得到4,然后将计算结果4再给 fun1 计算得到40;
indentity方法的用法:
JDK源码定义:
static <T> Function<T, T> identity() {
return t -> t;
}
public static void main(String[] args) {
System.out.println(Function.identity().apply("总分"));
}
上面打印出“总分“;就是说传入什么参数输出什么参数。
Predicate为函数式接口,predicate的中文意思是“断定”,即判断的意思,判断某个东西是否满足某种条件; 因此它包含test方法,根据输入值来做逻辑判断,其结果为True或者False。
test方法的用法:
JDK源码定义:
boolean test(T t);
public static void main(String[] args) {
Predicate<String> pre = res -> res.equals("1234");
boolean rest = pre.test("1234");
System.out.println(rest);
}
上面打印出true。
and方法的用法:
JDK源码定义:
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
public static void main(String[] args) {
Predicate<String> pre = res -> res.equals("1234");
Predicate<String> pre1 = res -> res.equals("1234");
Predicate<String> pre3 = res -> res.equals("1234");
boolean rest = pre.and(pre1).test("1234");
boolean rest1 = pre.and(pre1).test("12341");
System.out.println(rest);
System.out.println(rest1);
}
上面先打印出true,后打印出false
根据源码,"1234"先和pre比较,如果为true,再和pre1比较。不为true直接返回false,不再和pre1比较。当“1234”和pre比较后为true,再和pre1比较结果为true,所以最终返回true。
negate()的用法:
JDK源码定义
default Predicate<T> negate() {
return (t) -> !test(t);
}
public static void main(String[] args) {
Predicate<String> pre = res -> res.equals("1234");
boolean rest = pre.negate().test("1234");
System.out.println(rest);
}
上面打印出false,上面的意思是如果比较的结果是true,那么返回false,如果为false,就返回true。
or的方法的用法:
JDK源码定义:
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
public static void main(String[] args) {
Predicate<String> pre = res -> res.equals("1234");
Predicate<String> pre1 = res -> res.equals("12341");
boolean rest = pre.or(pre1).test("12341");
System.out.println(rest);
}
上面打印出true;or方法的意思是:只要一个为true就返回true。
isEqual方法用法:
JDK源码定义:
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
public static void main(String[] args) {
System.out.println(Predicate.isEqual("12345").test("12345"));
}
上面打印出true;isEqual里的参数是要比较的目标对象。
通过Stream以及Optional两个类,可以进一步利用函数式接口来简化代码。
Stream可以对多个元素进行一系列的操作,也可以支持对某些操作进行并发处理。
3.1.1 方法
Stream对象提供多个非常有用的方法,这些方法可以分成两类:
所有中间操作:
所有的终端操作:
Optional用于简化Java中对空值的判断处理,以防止出现各种空指针异常。
Optional实际上是对一个变量进行封装,它包含有一个属性value,实际上就是这个变量的值。
3.2.1 方法
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。