本人小白一枚,欢迎大家一起讨论学习,如有错误,还望大家指教。
简述:
函数式接口,即适用于函数式编程场景的接口,而Java中的函数式编程体现就是Lambda,所以函数式接口就是可以适用于Lambda使用的接口。只有确保接口中有且仅有一个抽象方法,才可以让Java中的Lambda语法顺利的进行推导。
格式:
定义一个接口且该接口仅有一个抽象方法,在Java8中专门为函数式接口引入了一个新的注解:@FunctionalInterface
。该注解可用于定义函数式接口,并且被该注解修饰后,编译器将会强制检查该接口是否仅有一个抽象方法,否则将会报错。注意:可以不使用该注解定义函数式接口,只要符合函数式接口的定义,该接口也是一个函数式接口,使用该注解可以增强代码的阅读性和规范性。
// 也可以使用@FunctionalInterface注解
public interface 接口名 {
public abstract 返回值类型 方法名称(可选参数信息);
}
常用函数式接口
JDK提供了大量常用的函数式接口以丰富Lambda的典型使用场景,他们主要在java.util.function
包中。下面我们简单了解几个。
一、Supplier接口(供给型接口)
该接口提供一个无参方法:T get()。用来获取一个泛型参数指定的对象数据。由于这是一个函数式接口,这也就意味对应的Lambda表达式需要对外提供一个符合泛型类型的对象数据。
例子:使用该接口求数组元素的最大值,该接口作为方法参数类型
public static void main(String[] args) {
Integer[] arr = new Integer[] {5, 48, 12, 99, 2, 7};
int max = getMax(() -> {
int num = arr[0];
for(int item : arr) {
if (num < item) {
num = item;
}
}
return num;
});
System.out.println("最大值为:" + max);
}
public static Integer getMax(Supplier<Integer> supplier) {
return supplier.get();
}
最大值为:99
二、Consumer接口(消费性接口)
java.util.function.Consumer<T>接口
则正好与Supplier接口
相反,它不是生产一个数据,而是消费一个数据,其数据类型有泛型来决定。该接口提供一个抽象有参方法: void accept(T t) ,意为消费一个指定泛型的数据。还提供一个默认方法:Consumer<T> andThen(Consumer<? super T> var),下面是JDK的源代码:
// java.util.Objects 的 requireNonNull 静态方法将会在参数为null时主动抛出,
// NullPointerException 异常。这省去了重复编写if语句和抛出空指针异常的麻烦。
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) ‐> { accept(t); after.accept(t); };
}
例子:将字符串数组按照:“姓名:xx,性别:xx”的格式将信息打印出来。
public static void main(String[] args) {
String[] array = {"迪丽热巴,女", "古力娜扎,女", "马尔扎哈,男"};
myAndThen((s) -> System.out.print("姓名:" + s.split(",")[0]),
(s) -> System.out.println(",年龄:" + s.split(",")[1]),
array);
}
public static void myAndThen(Consumer<String> one, Consumer<String> two, String[] array) {
for (String str : array) {
one.andThen(two).accept(str);
}
}
姓名:迪丽热巴,年龄:女
姓名:古力娜扎,年龄:女
姓名:马尔扎哈,年龄:男
三、Predicate接口(断言型接口)
当我们需要对某种类型的数据进行判断,从而得到一个boolean值结果时,这时就可以使用java.util.function.Predicate<T>接口
。该接口提供了一个抽象方法:boolean test(T t),用于条件判断的场景。
该接口还提供一个默认方法:default Predicate<T> and(Predicate<? super T> other)
,此方法将两个predicate
条件使用与逻辑连接起来使用并且的效果,下面为JDK源码:
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) ‐> test(t) && other.test(t);
}
例子:判断一个字符串既要包含大写“H”又要包含大写“W”。
public static void main(String[] args) {
boolean flag = checkString("aHdfWh", str -> str.contains("H"), str -> str.contains("W"));
System.out.println(flag);
}
public static boolean checkString(String str, Predicate<String> one, Predicate<String> two) {
return one.and(two).test(str);
}
默认方法or:default Predicate<T> or( Predicate<? super T> other)
,该方法与and方法类似,实现逻辑关系中的“或”,其下为源码:
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) ‐> test(t) || other.test(t);
}
默认方法非:default Predicate<T> negate( )
,该方法实现逻非(取反),以下为该方法的源代码:
default Predicate<T> negate() {
return (t) ‐> !test(t);
}
例子:判断字符串的长度是否小于小等于5。
private static boolean method(String str, Predicate<String> predicate) {
return predicate.negate().test(str);
}
public static void main(String[] args) {
boolean flag = method("abcd56", (str) -> str.length() > 5);
System.out.println(flag);
}
四、Function接口(功能型接口)
java.util.function.Function<T,R>
接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件。
抽象方法apply:R apply(T t) 该接口最主要的抽象方法,根据类型T的参数获取类型R的结果。
默认方法andThen:用来进行组合操作,源码如下:
default <V> Function<T, V> andThen(Function<? super R,? extends V> after) {
objects . requireNonNull ( after);
return (T t) -> after . app1y(app1y(t));
例子:将字符串截取数字年龄部分,得到字符串,将得到的字符串转换为int类型的数字,将数字加上100并返回
public static void main(String[] args) {
System.out.println(method("赵丽颖,20",
str -> str.split(",")[1],
str -> Integer.parseInt(str),
num -> num += 100));
}
public static Integer method(String str, Function<String, String> one, Function<String, Integer> two, Function<Integer, Integer> three) {
return one.andThen(two).andThen(three).apply(str);
}