写在前面
我们最常用的面向对象编程(Java)属于命令式编程
(Imperative Programming)这种编程范式。常见的编程范式还有逻辑式编程
(Logic Programming),函数式编程
(Functional Programming)。众所周知从Java 8开始引入了Lambda表达式,我们可以把它理解为一段可以传递的代码,可以写出更简洁、更灵活的代码。其基础内容不过多赘述,比如->、() 、{}
符号含义,匿名函数,闭包,集合Stream操作等,本文重点探讨一下Java内置的函数式接口。
@FunctionInterface函数式接口标注
JDK1.8 API中包含了很多内置的函数式接口(例如Runnable、Callable、Comparator、FileFilter等),我们可以发现他们都用@FunctionalInterface注解来进行了标注。
关于FunctionInterface注解:
1、该注解只能标记在 的接口上。
1.1、JDK8接口中的静态方法和默认方法,都不算是抽象方法。
1.2、接口默认继承java.lang.Object,所以如果接口显示声明覆盖了Object中方法,那么也不算抽象方法。
2、,加上该注解能够更好地让编译器进行检查。
Predicate 断言型接口 有入参|返回真假
Stream中的filter使用的就是此函数式接口。其包含了多种默认方法,用于处理复杂的逻辑动词(and, or,negate),用于Predicate的复合,进行复杂判断,示例如下:
// 示例1:初试
Predicate<String> predicate = new Predicate<String>() {
@Override
public boolean test(String x) {
// 验证逻辑
return x.contains("predicate");
}
};
// 可以简写为 Predicate<String> predicate = x -> x.contains("predicate");
System.out.println(predicate.test("Test predicate"));
// 示例2:复合
Predicate<String> predicate1 = x -> x.contains("predicate");
Predicate<String> predicate2 = x -> x.contains("Test");
String param = "Test predicate";
// 先写逻辑 后传参数
System.out.println(predicate1.and(predicate2).test(param));
Consumer 消费型接口 有入参|无返回值
顾名思义,给定一个参数,对其进行任何操作(消费)处理。其包含了andThen方法,传入一个Consumer,返回的仍然是Consumer,以此实行链式调用,示例如下:
// 示例1:初试
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println("执行逻辑 ------ 打印参数 : " + s);
}
};
// 可简写为 Consumer<String> consumer = s -> System.out.println("执行逻辑 ------ 打印参数 : " + s);
consumer.accept("Test Consumer");
// 示例2:复合
Consumer<String> consumer1 = s -> System.out.println("执行逻辑1 ------ 打印参数 : " + s);
Consumer<String> consumer2 = s -> System.out.println("执行逻辑2 ------ 打印参数 : " + s);
consumer1.andThen(consumer2).accept("Test Consumer");
Supplier 供给型接口 无入参|有返回值
同样顾名思义,执行后返回这个get方法的内容,我们可能会想没有参数,直接返回的为什么不直接定义一个常量呢?但是如果结果不是固定的,由具体get中的逻辑执行后得出,就不能使用常量了。
比如我们return "Test Supplier" + System.currentTimeMillis()
;
// 示例:初试
Supplier<String> supplier = new Supplier<String>() {
@Override
public String get() {
return "Test Supplier";
}
};
// 可简写为 Supplier<String> supplier = () -> "Test supplier";
System.out.println(supplier.get());
Function<T,R>函数式接口 有入参|有返回值
如果基于之上的Consumer和Supplier,我们去理解Function,就太简单了。这个就跟我们初中学的函数一样了,Function同时提供了compose(之前执行)和andThen(之后执行),可以进行复合操作,示例如下:
// 示例1:初试
Function<String, Integer> function = new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return s.length();
}
};
// 可简写为 Function<Integer, String> function = x -> "This is Integer:" + x;
System.out.println(function.apply("Test Function"));
// 示例2:复合
Function<String, Integer> function1 = s -> s.length();
Function<String, String> function2 = s -> s.replaceAll("Function", "");
System.out.println(function1.compose(function2).apply("Test Function"));
Consumer、Predicate、Function复合 怎么优雅怎么来
上面是单独的复合,当然他们也可以进行任何组合的复合,这样写的代码就更优雅了。
// Supplier、Consumer、Function复合
Supplier<String> supplier = () -> "Test Function & Supplier";
Consumer<String> consumer = s -> System.out.println("执行逻辑 ------ 打印参数 : " + s);
Function<String, Integer> function1 = s -> {
// Function执行添加Consumer打印参数逻辑
consumer.accept(s);
return s.length();
};
Function<String, String> function2 = s -> s.replaceAll("Function", "");
// 将Function的参数改为Supplier
System.out.println(function1.compose(function2).apply(supplier.get()));
集合Stream流中的函数式编程
.filter()
里面需要传入Predicate,根据test结果返回Optional。
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
.forEach()
里面需要传入Consumer,单纯的执行一段业务逻辑。
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
.map()
里需要传入Function,支持数据的自定义转换。
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Optional.ofNullable(mapper.apply(value));
}
}
在你完全理解函数式接口之后,很多源码的封装套路就一目了然了。
作者:舞鹤Roc
链接:https://www.jianshu.com/p/a7c2e4130349
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
网友评论