Java中的函数式接口详解(一)
- 2026-07-23 03:19:11
1. 函数式接口1.1. 定义函数式接口(Function Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
函数式接口又称为:功能接口。
功能接口为 Lambda 表达式和方法引用(用双冒号 ::来进行方法调用)提供目标类型!每个功能接口都有一个抽象方法,称为该功能接口的功能方法。Lambda 表达式的参数和返回类型要与功能方法的参数和返回值类型匹配或适配。
JDK8 开始,为函数式接口引入了一个新注解:@FunctionalInterface,主要用于编译级错误检查。
当接口加上了此注解后,如果接口不符合函数式接口的定义,则会报错。
注意:此注解不是编译器将接口识别为功能接口的必要条件,仅仅是帮助捕获设计意图并获得编译器帮助识别意外违反设计意图的帮助。
eg:
代码语言:javascript复制@FunctionalInterface
public interface HelloWorldService {
void sayHello(String msg);
}代码语言:javascript复制@FunctionalInterface
public interface HelloWorldService {
void sayHello(String msg);
void sayWorld();
}接口中只需要有且仅有一个抽象方法即可称为:函数式接口。此接口中可以存在默认方法、静态方法、Object 包下的 public 方法。下面,我将分别演示一遍。
1.2. 允许存在默认方法函数式接口里面是可以包含默认方法的,因为默认方法不是抽象方法,有一个默认实现,所以是符合函数式接口的定义。
代码语言:javascript复制@FunctionalInterface
public interface HelloWorldService {
void sayHello(String msg);
default void doSomeWork1() {
// Method body
System.sout.println("做作业");
}
default void doSomeWork2() {
// Method body
System.sout.println("打游戏");
}
}1.3. 允许存在静态方法函数式接口里面是可以包含静态方法的,因为静态方法不是抽象方法,是一个已经实现了的方法,所以是符合函数式接口的定义。
代码语言:javascript复制@FunctionalInterface
public interface HelloWorldService {
void sayHello(String msg);
static void printHello() {
System.out.println("Hello");
}
}1.4. 允许存在Java.Lang.Object类中的 public 方法函数式接口是可以包含 Object 类里的 public 方法。因为每一个函数式接口的实现,最顶层都默认继承了 Object 类,包含了来自 java.lang.object类中对这些抽象方法的实现
代码语言:javascript复制@FunctionalInterface
public interface HelloWorldService {
void sayHello(String msg);
// Object 类中的方法
@Override
boolean equals(Object obj);
}2. Function 函数接口2.1. 分类序号
接口名
描述
1
Function
接收一个参数并返回结果的函数
2
BiFunction
接受两个参数并返回结果的函数
3
DoubleFunction
接收一个 double 类型的参数并返回结果的函数
4
DoubleToIntFunction
接收一个 double 类型的参数并返回 int 结果的函数
5
DoubleToLongFunction
接收一个 double 类型的参数并返回 long 结果的函数
6
IntFunction
接收一个 int 类型的参数并返回结果的函数
7
IntToDoubleFunction
接收一个 int 类型的参数并返回 double 结果的函数
8
IntToLongFunction
接收一个 int 类型的参数并返回 long 结果的函数
9
LongFunction
接收一个 long 类型的参数并返回结果的函数
10
LongToDoubleFunction
接收一个 long 类型的参数并返回 double 结果的函数
11
LongToIntFunction
接收一个 long 类型的参数并返回 int 结果的函数
12
ToDoubleBiFunction
接收两个参数并返回 double 结果的函数
13
ToDoubleFunction
接收一个参数并返回 double 结果的函数
14
ToIntBiFunction
接收两个参数并返回 int 结果的函数
15
ToIntFunction
接收一个参数并返回 int 结果的函数
16
ToLongBiFunction
接收两个参数并返回 long 结果的函数
17
ToLongFunction
接收一个参数并返回 long 结果的函数
下面,博主将介绍几种常见Function函数的使用方法。
2.2. Function
代码语言:javascript复制@FunctionalInterface
public interface Function
/**
* 将形参 t 作为参数传递到此函数中
*
* @param t 函数参数
* @return 函数结果
*/
R apply(T t);
/**
* 返回一个组合函数,该函数首先将 before 函数应用于输入,然后再将此函数应用于结果。如果
* 任一函数的求值抛出异常,则会转发到该组合函数的调用者
*
* @param before 应用此函数之前要应用的函数
* @return 先应用 before 函数,然后应用此函数的组合函数
* @throws NullPointerException
*/
default
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
/**
* 返回一个组合函数,该函数首先将此函数应用于其输入,然后将 after 函数应用于结果。
* 如果对任一函数的求值抛出异常,则将其转发给组合函数的调用者。
*
* @param after 应用此函数后要应用的函数
* @return 一个组合函数,首先应用此函数,然后应用 after 函数
* @throws NullPointerException
*/
default
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
/**
* 返回一个始终返回其输入参数的函数。
*
* @return 始终返回其输入参数的函数
*/
static
return t -> t;
}
}方法:
接口方法
方法描述
R apply(T t)
将 t 参数应用到函数中
Function
返回一个组合函数,将该函数结果应用到 after 函数中
Function
返回一个组合函数,首先将入参应用于 before 函数中,再将 before 函数结果应用到该函数中
Function
返回一个始终返回该输入参数的函数
方法示例:
R apply(T t)代码语言:javascript复制@PostMapping(value = "/findAd")
public MerchantResult findAd(@RequestBody MerchantRequest request) {
return handleMerchantResult(request, currencyService::findAd);
}
/**
* 统一包装返回结果
*
* @param request 请求实体对象
* @param serviceFunction 服务函数
* @return 统一返回结果对象
*/
private MerchantResult handleMerchantResult(MerchantRequest request, Function
try {
// 将前端传递过来的参数应用到对应service层的方法中
return serviceFunction.apply(request);
} catch (ServiceException e) {
return MerchantResult.error(request.getMerchantId(), request.getRequestId(), e.getMessage());
}
}代码语言:javascript复制Function
System.out.println(function.apply("Hello")); // Hello Jack!Function
Function
String greet = function.andThen(function1).apply("Hello");
System.out.println(greet); // Hello Jack! Bob!Function
Function
String greet = function.compose(function1).apply("Hello");
System.out.println(greet); // Hello Bob! Jack!Function
List
list.stream().collect(Collectors.toMap(Student::getStudentId, Function.identity()));2.3. BiFunction
代码语言:javascript复制@FunctionalInterface
public interface BiFunction
/**
* 将此函数应用于给定的两个参数。
*
* @param t 第一个函数参数
* @param u 第二个函数参数
* @return 函数结果
*/
R apply(T t, U u);
/**
* 返回一个组合函数,该函数首先将此函数应用于其输入,然后将 after 函数应用于结果。
* 如果对任一函数的求值抛出异常,则将其转发给组合函数的调用者。
*
* @param after 应用此函数后要应用的函数
* @return 一个组合函数,首先应用此函数,然后应用 after 函数
* @throws NullPointerException
*/
default
Objects.requireNonNull(after);
return (T t, U u) -> after.apply(apply(t, u));
}
}方法:
接口方法
方法描述
R apply(T t, U u)
将两个参数应用于函数执行
BiFunction
返回一个组合函数,after函数应用于该函数之后
方法示例:
R apply(T t, U u)代码语言:javascript复制BiFunction
System.out.println(biFunction.apply("Hello ", "Jack!")); // Hello Jack!BiFunction
Function
System.out.println(biFunction.andThen(function).apply("Hello", "Jack")); // Hello Jack!!!2.4. DoubleFunction
代码语言:javascript复制@FunctionalInterface
public interface DoubleFunction
/**
* 根据给定 double 类型的参数执行函数
*
* @param value 函数参数
* @return 函数结果
*/
R apply(double value);方法:
接口方法
方法描述
R apply(double value)
将给定Double类型的参数应用于函数
方法示例:
R apply(T t, U u)代码语言:javascript复制DoubleFunction
System.out.println(doubleFunction.apply(1.6)); // 结果:1.62.5. DoubleToIntFunction源码:
代码语言:javascript复制@FunctionalInterface
public interface DoubleToIntFunction {
// 将给定的 double 类型的数据转换成 int 类型
int applyAsInt(double var1);
}方法:
接口方法
方法描述
int applyAsInt(double value)
将给定Double类型参数应用于函数,并转换成Int类型
方法示例:
int applyAsInt(double value)代码语言:javascript复制DoubleToIntFunction doubleToIntFunction = doub -> {
System.out.println("值为:" + doub);
return doub.intValue();
};
System.out.println(doubleToIntFunction.applyAsInt(1.2)); // 值为:1.2 12.6. ToDoubleBiFunction
代码语言:javascript复制@FunctionalInterface
public interface ToDoubleBiFunction
/**
* 将此函数应用于给定的参数。
*
* @param t 第一个函数参数
* @param u 第二个函数参数
* @return 函数结果
*/
double applyAsDouble(T t, U u);
}方法:
接口方法
方法描述
double applyAsDouble(T value)
根据给定的两个参数执行函数
方法示例:
double applyAsDouble(T value)代码语言:javascript复制ToDoubleBiFunction
System.out.println(toDoubleBiFunction.applyAsDouble(11L, 235.5f)); // 246.52.7. ToDoubleFunction
代码语言:javascript复制@FunctionalInterface
public interface ToDoubleFunction
/**
* 将此函数应用于给定的参数
*
* @param value 函数参数
* @return 函数结果
*/
double applyAsDouble(T value);
}方法:
接口方法
方法描述
double applyAsDouble(T value)
根据给定的一个参数执行函数
方法示例:
double applyAsDouble(T value)代码语言:javascript复制ToDoubleFunction
System.out.println(toDoubleFunction.applyAsDouble(12315f)); // 12315.03. Consumer 消费者接口3.1. 分类序号
接口
描述
1
Consumer
提供一个 T 类型的输入参数,不返回执行结果
2
BiConsumer
提供两个自定义类型的输入参数,不返回执行结果
3
DoubleConsumer
表示接受单个 Double 类型参数,但不返回结果的操作
4
IntConsumer
表示接受单个 Int 类型参数,但不返回结果的操作
5
LongConsumer
表示接受单个 Long 类型参数,但不返回结果的操作
6
ObjDoubleConsumer
表示接受 Object 类型和 Double 类型参数,但是不返回任何操作结果
7
ObjIntConsumer
表示接受 Object 类型和 Int 类型,但是不返回任何操作结果
8
ObjLongConsumer
表示接受 Object 类型和 Long 类型,但是不返回任何操作结果
下面,博主将介绍几种常见Consumer函数的使用方法。
3.2. Consumer
代码语言:javascript复制@FunctionalInterface
public interface Consumer
/**
* 对给定的参数执行此操作
*
* @param t 输入参数
*/
void accept(T t);
/**
* 返回一个组合的Consumer,该Consumer按顺序执行此操作,然后执行after操作。
* 如果执行任一操作都会引发异常,则会将其转发给组合操作的调用者。如果执行此操作会引发异常,则不会执行 after 操作。
*
* @param after 此操作后要执行的操作
* @return 一个组合的消费者,按顺序执行此操作,然后执行 after 操作
* @throws NullPointerException
*/
default Consumer
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}方法:
接口方法
方法描述
void accept(T t, U u)
对给定的参数执行操作
default Consumer andThen(Consumer super T> after)
返回一个组合函数,after 将会在该函数执行之后执行
方法示例:
void accept(T t, U u)代码语言:javascript复制StringBuilder sb = new StringBuilder("Hello ");
Consumer
consumer.accept(sb);
System.out.println(sb.toString()); // Hello Jack!default Consumer andThen(Consumer super T> after)代码语言:javascript复制StringBuilder sb = new StringBuilder("Hello");
Consumer
Consumer
consumer.andThen(consumer1).accept(sb);
System.out.println(sb.toString()); // Hello Jack! Bob!3.3. BiConsumer
代码语言:javascript复制@FunctionalInterface
public interface BiConsumer
/**
* 对给定的参数执行此操作
*
* @param t 第一个输入参数
* @param u 第二个输入参数
*/
void accept(T t, U u);
/**
* 返回一个组合的BiConsumer,该BiConsumer按顺序执行此操作,然后执行after操作。
* 如果执行任一操作都会引发异常,则会将其转发给组合操作的调用者。如果执行此操作会引发异常,则不会执行 after 操作。
*
* @param after 此操作后要执行的操作
* @return a 一个组合的 BiConsumer,按顺序执行此操作,然后执行 after 操作
* @throws NullPointerException
*/
default BiConsumer
Objects.requireNonNull(after);
return (l, r) -> {
accept(l, r);
after.accept(l, r);
};
}
}方法:
接口方法
方法描述
void accept(T t, U u)
对给定的参数执行操作
default BiConsumer
返回一个组合函数,after 将会在该函数执行之后执行
方法示例:
void accept(T t, U u)代码语言:javascript复制StringBuilder sb = new StringBuilder();
BiConsumer
sb.append(a);
sb.append(b);
};
biConsumer.accept("Hello ", "Jack!");
System.out.println(sb.toString()); // Hello Jack!default BiConsumer
BiConsumer
sb.append(a);
sb.append(b);
};
BiConsumer
System.out.println(a + b);
};
biConsumer.andThen(biConsumer1).accept("Hello", " Jack!"); // Hello Jack!3.4. DoubleConsumer源码:
代码语言:javascript复制@FunctionalInterface
public interface DoubleConsumer {
/**
* 对给定的参数执行此操作
*
* @param value 输入参数
*/
void accept(double value);
/**
* 返回一个组合的DoubleConsumer,它按顺序执行此操作,然后执行after操作。
* 如果执行任一操作都会引发异常,则会将其转发给组合操作的调用者。如果执行此操作会引发异常,则不会执行 after 操作。
*
* @param after 此操作后要执行的操作
* @return 一个组合的DoubleConsumer,按顺序执行此操作,然后执行 after 操作
* @throws NullPointerException
*/
default DoubleConsumer andThen(DoubleConsumer after) {
Objects.requireNonNull(after);
return (double t) -> { accept(t); after.accept(t); };
}方法:
接口方法
方法描述
void accept(double value)
对给定的参数执行操作
default DoubleConsumer andThen(DoubleConsumer after)
返回一个组合函数,after 在该函数执行之后执行
方法示例:
void accept(double value)代码语言:javascript复制DoubleConsumer doubleConsumer = System.out::println;
doubleConsumer.accept(1.3); // 1.3default DoubleConsumer andThen(DoubleConsumer after)代码语言:javascript复制DoubleConsumer doubleConsumer = (a) -> Integer.parseInt(a);
DoubleConsumer doubleConsumer1 = System.out::println;
doubleConsumer.andThen(doubleConsumer1).accept(1.3); // 13.5. ObjDoubleConsumer
代码语言:javascript复制@FunctionalInterface
public interface ObjDoubleConsumer
/**
* 对给定的参数执行此操作
*
* @param t 第一个输入参数
* @param value 第二个输入参数
*/
void accept(T t, double value);
}方法:
接口方法
方法描述
void accept(double value)
对给定的参数执行操作
方法示例:
void accept(double value)代码语言:javascript复制ObjDoubleConsumer
-> System.out.println(obj + doub);
doubleConsumer.accept("金额:", 222.66); // 金额:222.66后话:这是第一篇文章,因为内容比较多,所以博主分成了两篇文章发布。第二篇文章里面有介绍Predicate、Supplier、Operator这三个函数式接口的使用。敬请期待~
