0Pricing
Java Academy · 课时

自定义函数式接口

使用 @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 反馈 — 无需本地设置。

此课程中的所有课时

  1. Function 与 BiFunction
  2. Supplier 与 Consumer
  3. Predicate 与组合
  4. 自定义函数式接口
← 返回 Java Academy