我知道函数接口意味着你可以拥有一个具有多个默认方法的抽象方法,但我想知道如何将其与Java中使用函数接口的真实示例/情况联系起来。
你能举一个有效的情况/例子吗?
提前感谢!
首先,注释@FunctionalInterface
由Java的内置功能接口Predicate
、Function
、Consumer
等使用
从另一方面来说,你可能想创建一个自定义的,如下所示:
@FunctionalInterface
public interface ThrowingConsumer<T> {
void accept(T t) throws CustomException;
}
然后您可以将其用作方法参数:
public <T, R> void doSomething(T value, ThrowingConsumer<T, R> consumer) {
// ...
}
然后这样称呼它:
doSomething(someValue, this::customConsumerMethodThrowingAnException);
值得一提的是,@FunctionalInterface
不是必需的。编译器将与任何满足要求的接口完美结合。
编译器处理它的方式类似于处理@Override
注释。即使没有它,代码也可以编译。但一旦添加,它就会使代码更清晰,对将来维护代码的人来说更安全。
在JDK8之前,我们一直有功能接口,但没有lambdas、方法引用等。
从JDK8开始,它们为lambda表达式、方法引用提供了目标类型,从而具有更好的可读性和更紧凑的代码。
例如,在Java-8之前,如果你想提供每次点击Button
组件时都会执行的一些逻辑,你可以这样做:
btn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
System.out.println("Hello World!");
}
});
这是庞大的,难以阅读和不够紧凑。因为EventHandler
根据定义是一个功能接口,也就是说,从jdk8开始,它有一个SAM
,你现在可以做:
btn.setOnAction(event -> System.out.println("Hello World!"));
您只看到您关心的代码部分,即单击按钮时要执行的逻辑。
此外,由于我们可以使用函数接口作为lambda表达式的目标类型&方法参考,这将在以下情况下有用:
- 将比较器传递给排序方法,例如
List.sort
、Stream.sorted
、Collections.sort
等 - 传递代码块以在单独的线程中运行任务
等等。。。
同时保持代码可读性、紧凑性和简洁性。
功能接口在Java-stream API中被广泛使用。
您没有理由创建自己的功能接口,除非java.util.function
中没有满足您要求的接口,或者功能接口的名称不可读,因此您可以创建自己的接口。
在创建功能接口时,还建议使用@FunctionalInterface
注释,但不是必需的(标准库经常使用此注释)。
这使编译器能够检查带注释的实体是否是具有单个抽象方法的接口,否则会出现错误。
这对于在重构代码时发现错误也很有帮助。
它们提供的主要用途之一是,函数接口的实例可以使用lambda表达式和方法引用创建,同时还可以使用构造函数。例如,功能接口Sample
定义为:
@FunctionalInterface
public interface Sample {
void ab();
}
可以在一行代码中实例化,如下所示:
Sample sample = () -> System.out.println("ab called");
然后在任何需要的地方调用:
sample.ab();
我将进一步引用java.util.function
包中的Javadoc:
功能接口可以在多个上下文中提供目标类型,例如分配上下文、方法调用或强制转换上下文:
// Assignment context Predicate<String> p = String::isEmpty; // Method invocation context stream.filter(e -> e.getSize() > 10)... // Cast context stream.map((ToIntFunction) e -> e.getSize())...
此外,此类接口可以用@FunctionalInterface
注释进行注释。
此注释不是编译器将接口识别为函数接口的要求,而只是捕获设计意图并在识别中寻求编译器的帮助意外违反设计意图
使用现有此类接口的概念也是一个值得注意的点,
编译器将满足函数接口定义的任何接口视为函数接口,而不管接口声明上是否存在FunctionalInterface
注释
用FunctionalInterface
标记的接口保证适用于需要具有适当参数和返回类型的lambda表达式的上下文。除此之外,它们没有任何用处。可能会有一些优化,但在所有情况下,都无关紧要
Lambdas是函数接口的实现。。。因此,要么隐式地(由编译器或在运行时),要么显式地(通过代码…赋值)使用它们。实际例子是
- 谓词:用于筛选的跨代码用法
- 函数:Map.conteFiAbsent("xxx",s->s.length())
- BiFunction:salaris.replaceAll((name,oldValue)->name.equals("Freddy")?oldValue:oldValue+10000)
- 使用者:List.forEach(name->System.out.println("Hello,"+name))