函数式接口,是指只定义了一个抽象方法的接口,它可以拥有多个非抽象方法,同时可以被隐式转换为 lambda 表达式
一、函数式接口
-
在 Java8 中,接口可以拥有默认方法 (即在类没有对方法进行实现时,其主体为方法提供默认实现的方法),哪怕有很多默认方法,只要一个接口只定义了一个抽象方法,它就仍然是一个函数式接口,此外我们将函数式接口的抽象方法的签名称为函数描述符
-
举例说明
// 下面哪些接口是函数式接口 public interface Adder { int add(int a, int b); } public interface SmartAdder extends Adder { int add(int a, int b); } public interface Nothing { }
-
只有 Adder 是函数式接口
-
SmartAdder 定义了两个叫做 add 的抽象方法,一个是其自身定义的,还有一个是从 Adder 继承得到的
-
Nothing 中没有定义抽象方法
-
-
-
在阅读源码的时候,我们会发现,函数式接口都会带有 @FunctionInterface 注解,该注解的主要作用是:强制规定当前接口为函数式接口,如果接口中存在两个及以上抽象方法,就会编译报错
二、函数式接口的使用
-
在 java.util.function 包下存在很多函数式接口,用于支持函数式编程,这里主要介绍下 Java8 核心的四大接口:Predicate、Consumer、Function、Supplier
-
Predicate (断言型接口)
-
Predicate<T> 接口中定义了一个名为 test 的抽象方法,它接收一个泛型 T 对象,并返回一个 boolean
-
举例说明
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); Predicate<Integer> predicate = i -> i % 2 == 0; List<Integer> evenList = list.stream().filter(predicate).collect(toList()); System.out.println(evenList); // [2, 4, 6, 8]
- filter 方法接收 predicate 对象作为参数,用于筛选偶数
-
-
Consumer (消费型接口)
-
Consumer<T> 接口中定义了一个名为 accept 的抽象方法,它接收一个泛型 T 对象,没有返回 (void)
-
举例说明
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); Consumer<Integer> consumer = System.out::print; list.forEach(consumer); // 123456789
- forEach 方法接收 consumer 对象作为参数,用于循环遍历
-
-
Function (函数型接口)
-
Function<T, R> 接口中定义了一个名为 apply 的抽象方法,它接收一个泛型 T 对象,并返回一个泛型 R 对象
-
举例说明
Function<Integer, Integer> function = i -> i * 2; List<Integer> strList = list.stream().map(function).collect(toList()); System.out.println(strList); // [2, 4, 6, 8, 10, 12, 14, 16, 18]
- map 方法接收 function 对象作为参数,用于将数值翻倍
-
-
Supplier (供给型接口)
-
Supplier<T> 接口中定义了一个名为 get 的抽象方法,它不接收参数,返回一个泛型 T 对象
Supplier<String> supplier = () -> "HelloWorld"; System.out.println(supplier.get()); // HelloWorld
- supplier 对象调用 get() 方法为输出提供内容
-
三、避免自动装箱
-
我们先来看下以下代码,是可以正确运行的,这是因为 Java 会将基本数据类型自动转换为其对应的引用类型
-
装箱:将基本数据类型转换为其对应的引用类型
-
拆箱:将引用类型转换为其对应的基本数据类型
List<Integer> list = new ArrayList<>(); for (int i = 0; i < 10; i++) { list.add(i); } System.out.println(list); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
-
-
在 Java8 中,定义了专门的函数式接口,以便在输入和输出都是基本数据类型的时候避免自动装箱
-
举例说明 (IntPredicate)
public interface IntPredicate { boolean test(int value); } // 无装箱 IntPredicate intPredicate = (int i) -> i % 2 == 0; intPredicate.test(100); // true // 有装箱 Predicate<Integer> predicate = (Integer i) -> i % 2 == 0; predicate.test(100); // true
- 在这里,使用 IntPredicate 就避免了对值 100 进行装箱操作
-
类似的还有 IntConsumer、IntFunction、LongConsumer、LongFunction、LongPredicate 等接口
-
转载:https://blog.csdn.net/Goodbye_Youth/article/details/106857165