目录
一. 函数式接口简介
1、什么是函数式接口?
如果在Java的接口中,有且只有一个抽象方法,那么这种接口就是函数式接口。函数式接口是使用Lambda表达式的前提条件。
2. 为什么要使用函数式接口?
在Java中不支持将函数作为一个数据,也就不能将函数作为方法的参数进行传递。因此给函数外加一层接口的声明,相当于为其穿上一件漂亮的外衣包装起来。如果需要将函数作为方法传递时,就可以传递函数所在接口的实现类对象,来间接的传递方法内容了。
3. 函数式接口定义
我们可以使用@FunctionalInterface注解来检查一个接口是否是一个函数式接口。放在接口定义的上方,如果接口是函数式接口,编译通过;如果不是,则编译失败。
二. 常用函数式接口
Java8中提供了一些常用的函数式接口,在使用类似功能的时候,不需要额外定义接口,直接使用jdk8中提供的即可。这里介绍如下4种:
- Consumer 接口
- Supplier 接口
- Function 接口
- Predicate 接口
-
Consumer 接口
-
用于表示接受一个参数且无返回值的操作。它只有一个抽象方法
accept(T t)
,用于对给定的参数执行操作。例如,在处理集合时,可以使用 Consumer 接口来对每个元素执行某种操作,如打印、修改等。
package java.util.function;
import java.util.Objects;
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
使用实例 :
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 遍历打印
numbers.forEach(value -> System.out.println("Hello, " + value));
// 迭代器
public interface Iterable<T> {
Iterator<T> iterator();
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
}
-
Supplier 接口
-
用于表示无参数且返回一个结果的操作。它只有一个抽象方法
get()
,用于获取结果。Supplier 接口常用于需要生成值而不需要任何输入参数的场景。
package java.util.function;
@FunctionalInterface
public interface Supplier<T> {
T get();
}
使用示例:
List<Integer> list1 = useSupplier(5, () -> (int) (Math.random() * 10 + 1));
// 返回n个满足某个规律的数
public static List<Integer> useSupplier(int count, Supplier<Integer> sup){
List<Integer> list = new ArrayList<>();
for (int i = 0; i < count; i++) {
Integer integer = sup.get();
list.add(integer);
}
return list;
}
-
Function 接口
-
表示接受一个参数并返回结果的函数。它有一个抽象方法
apply(T t)
,用于将输入参数应用到函数上并返回结果。Function 接口是函数式编程中的核心概念之一,允许将数据转换为另一种形式或执行特定的计算逻辑。
package java.util.function;
import java.util.Objects;
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
使用示例:
List<Person> persons = new ArrayList<>();
List<String> names = persons.stream().map(Person::getName).collect(Collectors.toList());
static class Person {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
-
Predicate 接口
-
表示一个参数的谓词(布尔值函数)。它有一个抽象方法
test(T t)
,用于评估给定的参数是否满足某个条件并返回布尔值。Predicate 接口常用于过滤、判断等场景,如检查集合中的元素是否满足某个条件。
package java.util.function;
import java.util.Objects;
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate<T> negate() {
return (t) -> !test(t);
}
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
使用示例:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.stream().filter((n) -> n % 2 == 0).forEach(System.out::println);
三、定义自己的函数式接口
package com.cjian.functionalinterface;
/**
* @Author: cjian
* @Date: 2024/6/7 17:16
* @Des:
*/
@FunctionalInterface
public interface MyFunctionInterface {
void out(String msg);
}
测试:
static void testMyFunctionInterface(String msg , MyFunctionInterface myFunctionInterface){
myFunctionInterface.out(msg);
}
testMyFunctionInterface("Hello cj!", msg -> System.out.println(msg));
可以看到我们可以将函数作为一个参数传递给方法。