JDK8的1个新特性就是支持函数式接口(Functional Interface)。
函数式接口就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
函数式接口可以被隐式转换为Lambda表达式。
我们也可以自行定义函数式接口,如:
@FunctionalInterface
interface GreetingService{void sayMessage(String message);
}
然后通过Lambda表达式来定义接口实现(JAVA8之前一般使用匿名类来实现):
public class GreetingServiceTest {public static void main(String[] args) {GreetingService greetingService = message -> {System.out.println("Hello " + message);};greetingService.sayMessage("Mary");}
}执行返回:Hello Mary
JDK8官方也为我们定义了一些常用的函数式接口,如下图所示:
接下来,我重点介绍其中比较重要的几个函数式接口。
Function<T, R>
接收1个输入参数,返回1个结果。
- 源码
@FunctionalInterface
public interface Function<T, R> {// 将T类型转化为R类型R apply(T t);// 先执行参数传入的Function,再执行本Functiondefault <V> Function<V, R> compose(Function<? super V, ? extends T> before) {Objects.requireNonNull(before);return (V v) -> apply(before.apply(v));}// 和compose相反,先执行本Function,再执行参数传入的Functiondefault <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {Objects.requireNonNull(after);return (T t) -> after.apply(apply(t));}// 静态方法,返回传入的泛型T自身static <T> Function<T, T> identity() {return t -> t;}
}
- 代码示例
public class FunctionTest {public static Integer calculate(Integer i, Function<Integer, Integer> function){return function.apply(i);}public static void main(String[] args) {Function<Integer, Integer> func1 = i -> {return i+5;};Function<Integer, Integer> func2 = i -> {return i*5;};System.out.println(calculate(6, func1));System.out.println(calculate(6, func2));System.out.println(calculate(6, func1.compose(func2)));System.out.println(calculate(6, func1.andThen(func2)));System.out.println(Function.identity().apply("6+5"));}
}执行输出:11
30
35
55
6+5
Supplier
生产函数,无参数,返回1个结果。
- 源码
@FunctionalInterface
public interface Supplier<T> {// 生产1个元素T get();
}
- 代码示例
public class SupplierTest {public static void main(String[] args) {Supplier<String> supplier = () -> {return "商品";};System.out.println(supplier.get());}
}执行输出:商品
Consumer
消费函数,接收1个输入参数并且无返回的操作。
- 源码
@FunctionalInterface
public interface Consumer<T> {// 消费输入tvoid accept(T t);// 先执行本接口的消费逻辑,再执行传入函数的消费逻辑default Consumer<T> andThen(Consumer<? super T> after) {Objects.requireNonNull(after);return (T t) -> { accept(t); after.accept(t); };}
}
- 代码示例
public class ConsumerTest {public static void main(String[] args) {Consumer<String> consumer1 = s -> {System.out.println(s + ",我是消费者1");};Consumer<String> consumer2 = s -> {System.out.println(s + ",我是消费者2");};consumer1.accept("铁甲小宝");System.out.println("################");consumer1.andThen(consumer2).accept("铁甲小宝");}
}执行输出:铁甲小宝,我是消费者1
################
铁甲小宝,我是消费者1
铁甲小宝,我是消费者2
Predicate
断言函数,接受1个输入参数,返回1个布尔值结果。
- 源码
@FunctionalInterface
public interface Predicate<T> {// 对输入进行断言boolean test(T t);// 函数并操作default Predicate<T> and(Predicate<? super T> other) {Objects.requireNonNull(other);return (t) -> test(t) && other.test(t);}// 函数取反default Predicate<T> negate() {return (t) -> !test(t);}// 函数或操作default Predicate<T> or(Predicate<? super T> other) {Objects.requireNonNull(other);return (t) -> test(t) || other.test(t);}// 是否相等static <T> Predicate<T> isEqual(Object targetRef) {return (null == targetRef)? Objects::isNull: object -> targetRef.equals(object);}// 取反@SuppressWarnings("unchecked")static <T> Predicate<T> not(Predicate<? super T> target) {Objects.requireNonNull(target);return (Predicate<T>)target.negate();}
}
- 代码示例
public class PredicateTest {public static void main(String[] args) {// 断言输入值是否大于10Predicate<Integer> isSuperTen = i -> {return i>10;};System.out.println(isSuperTen.test(11));System.out.println(isSuperTen.test(6));// 取反,断言输入值是否不大于10Predicate<Integer> negate = isSuperTen.negate();System.out.println(negate.test(6));// 断言输入值是否大于20Predicate<Integer> isLowerTwenty = i -> {return i<20;};// 断言15是否>10且<20System.out.println(isSuperTen.and(isLowerTwenty).test(15));// 断言21是否>10且<20System.out.println(isSuperTen.and(isLowerTwenty).test(21));// 断言21是否>10或<20System.out.println(isSuperTen.or(isLowerTwenty).test(21));}
}执行输出:true
false
true
true
false
true
BiFunction<T, U, R>
接受1个入参T和U,并返回结果R。
- 源码
@FunctionalInterface
public interface BiFunction<T, U, R> {// 根据输入t和u,转化为输出rR apply(T t, U u);// 先执行本函数,再执行参数传入的函数default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {Objects.requireNonNull(after);return (T t, U u) -> after.apply(apply(t, u));}
}
- 代码示例
public class BiFunctionTest {public static void main(String[] args) {BiFunction<String, Integer, String> biFunction = (key, value) -> {return (key + ":" + String.valueOf(value));};String key = "age";Integer value = 18;System.out.println(biFunction.apply(key, value));Function<String, String> afterFunction = s -> {System.out.println("执行后继函数,添加前缀***");return "***-" + s;};System.out.println(biFunction.andThen(afterFunction).apply(key, value));}
}执行输出:age:18
执行后继函数,添加前缀***
***-age:18
BiConsumer<T, U>
代表了1个接受2个输入参数的操作,并且不返回任何结果。
- 源码
@FunctionalInterface
public interface BiConsumer<T, U> {// 消费2个输入t和uvoid accept(T t, U u);// 先执行该函数的消费逻辑,再执行传入函数的消费逻辑default BiConsumer<T, U> andThen(BiConsumer<? super T, ? super U> after) {Objects.requireNonNull(after);return (l, r) -> {accept(l, r);after.accept(l, r);};}
- 代码示例
public class BiConsumerTest {public static void main(String[] args) {BiConsumer<String, Integer> biConsumer1 = (s, i) -> {System.out.println("我是消费逻辑1" + "," + s + "," + String.valueOf(i+10));};BiConsumer<String, Integer> biConsumer2 = (s, i) -> {System.out.println("我是消费逻辑2" + "," + s + "," + String.valueOf(i*3));};biConsumer1.accept("铁甲小宝", 6);System.out.println("###########");biConsumer1.andThen(biConsumer2).accept("铁甲小宝", 6);}
}执行输出:我是消费逻辑1,铁甲小宝,16
###########
我是消费逻辑1,铁甲小宝,16
我是消费逻辑2,铁甲小宝,18
BiPredicate<T, U>
对2个输入参数T和U进行断言,返回1个布尔值输出。
- 源码
@FunctionalInterface
public interface BiPredicate<T, U> {// 断言输入t和uboolean test(T t, U u);// 并操作default BiPredicate<T, U> and(BiPredicate<? super T, ? super U> other) {Objects.requireNonNull(other);return (T t, U u) -> test(t, u) && other.test(t, u);}// 取反default BiPredicate<T, U> negate() {return (T t, U u) -> !test(t, u);}// 或操作default BiPredicate<T, U> or(BiPredicate<? super T, ? super U> other) {Objects.requireNonNull(other);return (T t, U u) -> test(t, u) || other.test(t, u);}
}
- 代码示例
public class BiPredicateTest {public static void main(String[] args) {// 判断输入1是否大于10,且输入2小于20BiPredicate<String, Integer> biPredicate = (s, i) -> {return Integer.valueOf(s) > 10 && i < 20;};System.out.println(biPredicate.test("15", 16));System.out.println(biPredicate.test("15", 21));System.out.println(biPredicate.test("6", 21));}
}执行输出:true
false
false
其他函数接口基本原理类似,不再赘述。
之所以今天讲解一下JDK8的函数式编程,主要是为后续的Flink源码解析系列做一些前置知识储备,因为Flink源码里有大量的函数式接口实践。
本文到此结束,谢谢阅读!