Java 函数式接口

本文最后更新于:2024年3月18日 凌晨

Java 函数式接口

  • 函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
  • 函数式接口用注解 @FunctionalInterface 标注。
  • FunctionalInterface 允许传入:
    • 接口的实现类(传统写法,代码较繁琐)
    • Lambda 表达式(只需列出参数名,由编译器推断类型)
    • 符合方法签名的静态方法。
    • 符合方法签名的实例方法(实例类型被看做第一个参数类型)
    • 符合方法签名的构造方法(实例类型被看做返回类型)
  • FunctionalInterface 不强制继承关系,不需要方法名称相同,只要求方法参数(类型和数量)与方法返回类型相同,即认为方法签名相同。
  • 如定义了一个函数式接口如下。
1
2
3
4
5
@FunctionalInterface
interface GreetingService
{
void sayMessage(String message);
}
  • 那么就可以使用 Lambda 表达式来表示该接口的一个实现(注:JAVA 8 之前一般是用匿名类实现的):
1
GreetingService greetService1 = message -> System.out.println("Hello " + message);
  • 函数式接口可以对现有的函数友好地支持 lambda

实例

  • Comparator 为例,我们想要调用 Arrays.sort() 时,可以传入一个 Comparator 实例,以匿名类方式编写如下:
1
2
3
4
5
Arrays.sort(array, new Comparator<String>() {
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}
});
  • 接收 FunctionalInterface 作为参数的时候,可以把实例化的匿名类改写为 Lambda 表达式,能大大简化代码,Lambda 表达式的参数和返回值均可由编译器自动推断。
1
Arrays.sort(array, (s1, s2) -> s1.compareTo(s2));
  • 再来看 Comparator 接口:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@FunctionalInterface
public interface Comparator<T> {

int compare(T o1, T o2);

boolean equals(Object obj);

default Comparator<T> reversed() {
return Collections.reverseOrder(this);
}

default Comparator<T> thenComparing(Comparator<? super T> other) {
...
}
...
}
  • 虽然 Comparator 接口有很多方法,但只有一个抽象方法 int compare(T o1, T o2),其他的方法都是 default 方法或 static 方法,另外注意到 boolean equals(Object obj)Object 定义的方法,不算在接口方法内,因此,Comparator 也是一个 FunctionalInterface

函数式接口

  • JDK 1.8 之前已有的函数式接口:
    • java. lang. Runnable
    • java. util. concurrent. Callable
    • java. security. PrivilegedAction
    • java. util. Comparator
    • java. io. FileFilter
    • java. nio. file. PathMatcher
    • java. lang. reflect. InvocationHandler
    • java. beans. PropertyChangeListener
    • java. awt. event. ActionListener
    • javax. swing. event. ChangeListener
  • JDK 1.8 新增加的函数接口:
    • java. util. function 它包含了很多类,用来支持 Java 的函数式编程,该包中的函数式接口有:
接口 & 描述
Function<T,R>:接受一个输入参数,返回一个结果
Predicate<T>:接受一个输入参数,返回一个布尔值结果
Supplier<T>:无参数,返回一个结果
Consumer<T>:代表了接受一个输入参数并且无返回的操作
BiConsumer<T,U>:代表了一个接受两个输入参数的操作,并且不返回任何结果
BiFunction<T,U,R>:代表了一个接受两个输入参数的方法,并且返回一个结果
BinaryOperator<T>:代表了一个作用于于两个同类型操作符的操作,并且返回了操作符同类型的结果
BiPredicate<T,U>:代表了一个两个参数的 boolean 值方法
BooleanSupplier:代表了 boolean 值结果的提供方
DoubleBinaryOperator:代表了作用于两个 double 值操作符的操作,并且返回了一个 double 值的结果
DoubleConsumer:代表一个接受 double 值参数的操作,并且不返回结果
DoubleFunction<R>:代表接受一个 double 值参数的方法,并且返回结果
DoublePredicate:代表一个拥有 double 值参数的 boolean 值方法
DoubleSupplier:代表一个 double 值结构的提供方
DoubleToIntFunction:接受一个 double 类型输入,返回一个 int 类型结果
DoubleToLongFunction:接受一个 double 类型输入,返回一个 long 类型结果
DoubleUnaryOperator:接受一个参数同为类型 double,返回值类型也为 double
IntBinaryOperator:接受两个参数同为类型 int,返回值类型也为 int
IntConsumer:接受一个 int 类型的输入参数,无返回值
IntFunction<R>:接受一个 int 类型输入参数,返回一个结果
IntPredicate:接受一个 int 输入参数,返回一个布尔值的结果
IntSupplier:无参数,返回一个 int 类型结果
IntToDoubleFunction:接受一个 int 类型输入,返回一个 double 类型结果
IntToLongFunction:接受一个 int 类型输入,返回一个 long 类型结果
IntUnaryOperator:接受一个参数同为类型 int,返回值类型也为 int
LongBinaryOperator:接受两个参数同为类型 long,返回值类型也为 long
LongConsumer:接受一个 long 类型的输入参数,无返回值
LongFunction<R>:接受一个 long 类型输入参数,返回一个结果
LongPredicate:接受一个 long 输入参数,返回一个布尔值类型结果
LongSupplier:无参数,返回一个结果 long 类型的值
LongToDoubleFunction:接受一个 long 类型输入,返回一个 double 类型结果
LongToIntFunction:接受一个 long 类型输入,返回一个 int 类型结果
LongUnaryOperator:接受一个参数同为类型 long,返回值类型也为 long
ObjDoubleConsumer<T>:接受一个 object 类型和一个 double 类型的输入参数,无返回值
ObjIntConsumer<T>:接受一个 object 类型和一个 int 类型的输入参数,无返回值
ObjLongConsumer<T>:接受一个 object 类型和一个 long 类型的输入参数,无返回值
ToDoubleBiFunction<T,U>:接受两个输入参数,返回一个 double 类型结果
ToDoubleFunction<T>:接受一个输入参数,返回一个 double 类型结果
ToIntBiFunction<T,U>:接受两个输入参数,返回一个 int 类型结果
ToIntFunction<T>:接受一个输入参数,返回一个 int 类型结果,
ToLongBiFunction<T,U>:接受两个输入参数,返回一个 long 类型结果
ToLongFunction<T>:接受一个输入参数,返回一个 long 类型结果
UnaryOperator<T>:接受一个参数为类型 T,返回值类型也为 T

函数式接口实例

  • Predicate <T> 接口是一个函数式接口,它接受一个输入参数 T,返回一个布尔值结果。
  • 该接口包含多种默认方法来将 Predicate 组合成其他复杂的逻辑(比如:与,或,非)
  • 该接口用于测试对象是 true 或 false
  • 我们可以通过以下实例来了解函数式接口 Predicate <T> 的使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public class Java8Tester {
public static void main(String args[]){
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);

// Predicate<Integer> predicate = n -> true
// n 是一个参数传递到 Predicate 接口的 test 方法。
// n 如果存在则 test 方法返回 true

System.out.println("输出所有数据:");

// 传递参数 n
eval(list, n->true);

// Predicate<Integer> predicate1 = n -> n%2 == 0
// n 是一个参数传递到 Predicate 接口的 test 方法。
// 如果 n%2 为 0 test 方法返回 true

System.out.println("输出所有偶数:");
eval(list, n-> n%2 == 0 );

// Predicate<Integer> predicate2 = n -> n > 3
// n 是一个参数传递到 Predicate 接口的 test 方法。
// 如果 n 大于 3 test 方法返回 true

System.out.println("输出大于 3 的所有数字:");
eval(list, n-> n > 3 );
}

public static void eval(List<Integer> list, Predicate<Integer> predicate) {
for(Integer n: list) {
if(predicate.test(n)) {
System.out.println(n + " ");
}
}
}
}
  • 执行以上脚本,输出结果为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
输出所有数据:
1
2
3
4
5
6
7
8
9
输出所有偶数:
2
4
6
8
输出大于 3 的所有数字:
4
5
6
7
8
9

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!