1、什么是函数式接口
- 函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
- 你可以通过 Lambda 表达式来创建该接口的对象。(若 Lambda表达式抛出一个受检异常,那么该异常需要在目标接口的抽象方法上进行声明)。
- 我们可以在任意函数式接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口,同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。
-
在java.util.function包下定义了java 8 的丰富的函数式接口。
1.1、关于@FunctionalInterface注解
Java 8为函数式接口引入了一个新注解@FunctionalInterface,主要用于编译级错误检查,加上该注解,当你写的接口不符合函数式接口定义的时候,编译器会报错。
正确例子,没有报错:
@FunctionalInterface
interface GreetingService {
void sayMessage(String message);
}
错误例子,接口中包含了两个抽象方法,违反了函数式接口的定义,Eclipse 报错提示其不是函数式接口。

注意:加不加 @FunctionalInterface 对于接口是不是函数式接口没有影响,该注解只是提醒编译器去检查该接口是否仅包含一个抽象方法。
1.2、如何理解函数式接口
- Java从诞生日起就是一直倡导“一切皆对象”,在java里面面向对象(OOP)编程是一切。但是随着python、scala等语言的兴起和新技术的挑战,java不得不做出调整以便支持更加广泛的技术要求,也即java不但可以支持OOP还可以支持OOF(面向函数编程)
- 在函数式编程语言当中,函数被当做一等公民对待。在将函数作为一等公民的编程语言中,Lambda表达式的类型是函数。但是在Java8中,有所不同。在Java8中,Lambda表达式是对象,而不是函数,它们必须依附于一类特别的对象类型——函数式接口。
- 简单的说,在Java8中,Lambda表达式就是一个函数式接口的实例。这就是Lambda表达式和函数式接口的关系。也就是说,只要一个对象是函数式接口的实例,那么该对象就可以用Lambda表达式来表示。所以以前用匿名内部类表示的现在都可以用Lambda表达式来写。
2、自定义函数式接口

函数式接口中使用泛型:

3、作为参数传递 Lambda表达式

作为参数传递 Lambda表达式:

作为参数传递 Lambda表达式:为了将 Lambda 表达式作为参数传递,接收 Lambda表达式的参数类型必须是与该Lambda表达式兼容的函数式接口的类型。
3、Java内置四大核心函数式接口
|
函数式接口 |
参数类型 |
返回类型 |
用途 |
|
Consumer<T> 消费型接口 |
T |
void |
对类型为T的对象应用操作,包含方法: void accept(T t) |
|
Supplier<T> 供给型接口 |
无 |
T |
返回类型为T的对象,包含方法:T get() |
|
Function<T, R> 函数型接口 |
T |
R |
对类型为T的对象应用操作,并返回结果。结果是R类型的对象。包含方法:R apply(T t) |
|
Predicate<T> 断定型接口 |
T |
boolean |
确定类型为T的对象是否满足某约束,并返回 boolean 值。包含方法 boolean test(T t) |
4、其他接口
|
函数式接口 |
参数类型 |
返回类型 |
用途 |
|
BiFunction<T, U, R> |
T, U |
R |
对类型为 T, U 参数应用操作,返回 R 类型的结果。包含方法为 R apply(T t, U u); |
|
UnaryOperator<T> (Function子接口) |
T |
T |
对类型为T的对象进行一元运算,并返回T类型的结果。包含方法为 T apply(T t); |
|
BinaryOperator<T> (BiFunction 子接口) |
T, T |
T |
对类型为T的对象进行二元运算,并返回T类型的结果。包含方法为 T apply(T t1, T t2); |
|
BiConsumer<T, U> |
T, U |
void |
对类型为T, U 参数应用操作。包含方法为 void accept(T t, U u) |
|
BiPredicate<T,U> |
T,U |
boolean |
包含方法为 boolean test(T t,U u) |
|
ToIntFunction<T> ToLongFunction<T> ToDoubleFunction<T> |
T |
int long double |
分别计算int、long、double、值的函数 |
|
IntFunction<R> LongFunction<R> DoubleFunction<R> |
int long double |
R |
参数分别为int、long、double 类型的函数 |
5、函数式接口实例
Predicate <T> 接口是一个函数式接口,它接受一个输入参数 T,返回一个布尔值结果。
该接口包含多种默认方法来将Predicate组合成其他复杂的逻辑(比如:与,或,非)。
该接口用于测试对象是 true 或 false。
我们可以通过以下实例(Java8Tester.java)来了解函数式接口 Predicate <T> 的使用:
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 + " ");
}
}
}
}
执行以上脚本,输出结果为:
$ javac Java8Tester.java
$ java Java8Tester
输出所有数据:
1
2
3
4
5
6
7
8
9
输出所有偶数:
2
4
6
8
输出大于 3 的所有数字:
4
5
6
7
8
9
本文深入解析Java8中的函数式接口概念,包括@FunctionalInterface注解的作用、Lambda表达式与函数式接口的关系,以及Java内置的四大核心函数式接口(Consumer、Supplier、Function、Predicate)的详细用法。通过实例演示Predicate接口的应用,帮助读者掌握函数式编程在Java中的实践。
4165

被折叠的 条评论
为什么被折叠?



