自定义函数式接口
使用 @FunctionalInterface 定义自己的接口
自定义函数式接口 是 CoddyKit 上的免费 Java Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Java Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Java Academy 课程共包含 4 节课。
接口如何成为函数式接口
函数式接口恰好有一个抽象方法(SAM)。Lambda 表达式正是实现这个单一方法的方式。
- 默认方法和静态方法不会计入此限制。
interface Greeter {
String greet(String name);
}
public class Main {
public static void main(String[] args) {
Greeter g = name -> "Hello, " + name;
System.out.println(g.greet("Ada"));
}
}@FunctionalInterface 注解
@FunctionalInterface 会告诉编译器强制执行单一抽象方法规则。如果您意外添加了第二个抽象方法,编译就会失败。
@FunctionalInterface
interface Calculator {
int compute(int a, int b);
}
public class Main {
public static void main(String[] args) {
Calculator add = (a, b) -> a + b;
System.out.println(add.compute(3, 4));
}
}注解为何有帮助
该注解记录了设计意图并保护了契约。没有它,接口仍然可以作为函数式接口使用,但其他开发人员可能会通过添加另一个抽象方法破坏它。
@FunctionalInterface
interface Transformer {
String apply(String input);
}
public class Main {
public static void main(String[] args) {
Transformer reverse = s -> new StringBuilder(s).reverse().toString();
System.out.println(reverse.apply("abc"));
}
}带泛型的自定义接口
您的接口也可以使用泛型,就像内置接口一样。
@FunctionalInterface
interface Converter<S, T> {
T convert(S source);
}
public class Main {
public static void main(String[] args) {
Converter<String, Integer> toInt = Integer::parseInt;
System.out.println(toInt.convert("123") + 1);
}
}允许使用默认方法
函数式接口可以包含 default 方法。它们可以添加行为,同时不会破坏单一抽象方法规则。
@FunctionalInterface
interface Operation {
int apply(int x);
default Operation then(Operation next) {
return x -> next.apply(this.apply(x));
}
}
public class Main {
public static void main(String[] args) {
Operation inc = x -> x + 1;
Operation dbl = x -> x * 2;
System.out.println(inc.then(dbl).apply(5));
}
}同样允许使用静态方法
静态方法可以充当工厂方法,类似于 Function.identity()。
@FunctionalInterface
interface Mapper {
int map(int x);
static Mapper identity() {
return x -> x;
}
}
public class Main {
public static void main(String[] args) {
System.out.println(Mapper.identity().map(99));
}
}抛出受检异常
如果您的抽象方法声明了受检异常,Lambda 表达式就可以抛出该异常。内置的 Function 无法做到这一点,这也是定义自有接口的原因之一。
@FunctionalInterface
interface RiskyParser {
int parse(String s) throws NumberFormatException;
}
public class Main {
public static void main(String[] args) {
RiskyParser p = Integer::parseInt;
System.out.println(p.parse("77"));
}
}将自定义接口传递给方法
您的接口会成为参数类型,使调用者能够通过 Lambda 表达式提供行为。
@FunctionalInterface
interface IntCombiner {
int combine(int a, int b);
}
public class Main {
static int reduce(int[] arr, IntCombiner c) {
int acc = arr[0];
for (int i = 1; i < arr.length; i++) acc = c.combine(acc, arr[i]);
return acc;
}
public static void main(String[] args) {
int[] data = {1, 2, 3, 4};
System.out.println(reduce(data, (a, b) -> a + b));
}
}三参数接口
JDK 只提供单参数和双参数接口。对于三个或更多参数,请定义您自己的接口。
@FunctionalInterface
interface TriFunction<A, B, C, R> {
R apply(A a, B b, C c);
}
public class Main {
public static void main(String[] args) {
TriFunction<Integer, Integer, Integer, Integer> sum3 = (a, b, c) -> a + b + c;
System.out.println(sum3.apply(1, 2, 3));
}
}方法引用适用于自定义接口
只要某个方法的签名与 SAM 匹配,就可以将它作为方法引用提供。
@FunctionalInterface
interface StringTest {
boolean check(String s);
}
public class Main {
public static void main(String[] args) {
StringTest blank = String::isBlank;
System.out.println(blank.check(" "));
}
}匿名类与 Lambda 表达式
Lambda 表达式是实现函数式接口的匿名类的一种简洁替代方式。两者产生相同的行为。
@FunctionalInterface
interface Action {
void run();
}
public class Main {
public static void main(String[] args) {
Action old = new Action() {
public void run() { System.out.println("anonymous"); }
};
Action neo = () -> System.out.println("lambda");
old.run();
neo.run();
}
}快速检查
@FunctionalInterface 能保证什么?
回顾
您已经定义了自己的函数式接口:
- 函数式接口恰好有一个抽象方法(SAM)。
@FunctionalInterface会在编译时强制执行这一规则。- 默认方法和静态方法、泛型以及受检异常都是允许的。
- 自定义接口可以填补 JDK 未覆盖的空白,例如三参数函数或能够抛出受检异常的 Lambda 表达式。
常见问题解答
「自定义函数式接口」课时是免费的吗?
是的 — 「自定义函数式接口」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Java Academy 课程的其余内容,请升级到 CoddyKit PRO。 Java Academy 课程共包含 4 节课。
「自定义函数式接口」这节课中我会学到什么?
使用 @FunctionalInterface 定义自己的接口 你通过在浏览器中直接运行的动手代码来练习 Java Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Java Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Java Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「自定义函数式接口」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Java Academy 课中编写并运行代码吗?
能。每节 Java Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。