# 函数式接口
# 一、概述
# 1.1、什么是函数式接口?
只有一个抽象方法的接口我们称之为函数接口。
JDK的函数式接口都加上了**@FunctionalInterface** 注解进行标识。
但是无论是否加上该注解只要接口中只有一个抽象方法,都是函数式接口。
jdk自带的一些常用的一些接口Callable、Runnable、Comparator等在JDK8中都添加了@FunctionalInterface注解。
# 1.2、FunctionalInterface注解说明
- 该注解只能标记在"有且仅有一个抽象方法"的接口上。
- JDK8接口中的静态方法和默认方法,都不算是抽象方法。
- 接口默认继承java.lang.Object,所以如果接口显示声明覆盖了Object中方法,那么也不算抽象方法。
- 该注解不是必须的,如果一个接口符合"函数式接口"定义,那么加不加该注解都没有影响。
- 为了规范,建议给所有需要使用函数式编程的接口都加上注解。
# 二、自定义函数式接口
只有一个抽象方法的情况
@FunctionalInterface
public interface MyInterface {
int test(int i);
}
1
2
3
4
5
2
3
4
5
有多个方法,但只有一个抽象方法,其他方法有默认实现
@FunctionalInterface
public interface MyInterface {
int test(int i);
default int add(int a, int b) {
return a + b;
}
default void sum(int a, int b) {
System.out.println("sum:" + a + b);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
使用一下,看看效果
public static void main(String[] args) {
// 使用lombda实现test方法
MyInterface myInterface = i -> i*2;
// 调用刚刚实现的方法
System.out.println(myInterface.test(22));
// 调用默认重写的方法
System.out.println(myInterface.add(10,20));
myInterface.sum(100,20);
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
结果
44
30
sum:10020
1
2
3
2
3
# 三、JDK自带函数式接口
大多数情况下我们不需要自己去撰写函数式接口,因此jdk自带的函数接口应该是日常开发中,使用频率最高的函数式接口了,这里已经整理成表格的形式方便后续查阅使用。
接口 | 输入参数 | 返回类型 | 使用说明 |
---|---|---|---|
Predicate | T | boolean | 断言 |
Consumer | T | / | 消费一个数据 |
Function | T | R | 输入T输出R的函数 |
Supplier | / | T | 提供一个数据 |
UnaryOperator | T | T | 一元函数(输入输出类型相同) |
BiFunction | (T,U) | R | 两个输入的函数 |
BinaryOperator | (T,T) | T | 二元函数(输入输出类型相同) |
# 3.1、Consumer 消费接口
根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中对传入的参数进行消费。
# 3.2、Function 计算转换接口
根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中对传入的参数计算或转换,把结果返回
# 3.3、Predicate 判断接口
根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中对传入的参数条件判断,返回判断结果
# 3.4、Supplier 生产型接口
根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中创建对象,把创建好的对象返回
# 3.5、使用
public static void main(String[] args) {
// 断言
Predicate<Integer> predicate = i -> i > 0;
System.out.println(predicate.test(-1));
// 消费
Consumer<String> consumer = s -> System.out.println(s);
consumer.accept("张三");
// 输入T输出R
Function<Integer, String> function = i -> i >= 0 ? "正数" : "负数";
function.apply(7);
// 提供一个数据
Supplier<String> stringSupplier = () -> "测试";
System.out.println(stringSupplier.get());
// 一元函数
UnaryOperator<String> unaryOperator = s -> "处理后" + s;
System.out.println(unaryOperator.apply("Test"));
// 两个输入的函数
BiFunction<String,Boolean,Integer> biFunction = (s, b) -> {
// 如果b为true,返回0;如果s为test返回1,否则返回-1
if (b){
return 0;
}
if ("test".equals(s)){
return 1;
}
return -1;
};
System.out.println(biFunction.apply("test", false));
// 二元函数
BinaryOperator<String> binaryOperator = (s, s2) -> s+s2;
System.out.println(binaryOperator.apply("雷军", "666"));
}
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
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
结果
false
张三
测试
处理后Test
1
雷军666
1
2
3
4
5
6
2
3
4
5
6
# 四、常用的默认方法
and
我们在使用Predicate接口时候可能需要进行判断条件的拼接。而and方法相当于是使用&&来拼接两个判断条件
例如:
打印作家中年龄大于17并且姓名的长度大于1的作家。
List<Author> authors = getAuthors(); Stream<Author> authorStream = authors.stream(); authorStream.filter(new Predicate<Author>() { @Override public boolean test(Author author) { return author.getAge()>17; } }.and(new Predicate<Author>() { @Override public boolean test(Author author) { return author.getName().length()>1; } })).forEach(author -> System.out.println(author));
1
2
3
4
5
6
7
8
9
10
11
12
13or
我们在使用Predicate接口时候可能需要进行判断条件的拼接。而or方法相当于是使用||来拼接两个判断条件。
例如:
打印作家中年龄大于17或者姓名的长度小于2的作家。
// 打印作家中年龄大于17或者姓名的长度小于2的作家。 List<Author> authors = getAuthors(); authors.stream() .filter(new Predicate<Author>() { @Override public boolean test(Author author) { return author.getAge()>17; } }.or(new Predicate<Author>() { @Override public boolean test(Author author) { return author.getName().length()<2; } })).forEach(author -> System.out.println(author.getName()));
1
2
3
4
5
6
7
8
9
10
11
12
13
14negate
Predicate接口中的方法。negate方法相当于是在判断添加前面加了个! 表示取反
例如:
打印作家中年龄不大于17的作家。
// 打印作家中年龄不大于17的作家。 List<Author> authors = getAuthors(); authors.stream() .filter(new Predicate<Author>() { @Override public boolean test(Author author) { return author.getAge()>17; } }.negate()).forEach(author -> System.out.println(author.getAge()));
1
2
3
4
5
6
7
8
9