通过 lambda 表达式实现具有两个抽象方法的接口

Posted

技术标签:

【中文标题】通过 lambda 表达式实现具有两个抽象方法的接口【英文标题】:Implementing an interface with two abstract methods by a lambda expression 【发布时间】:2016-07-14 00:12:21 【问题描述】:

在 Java 8 中引入了 lambda 表达式 来帮助减少样板代码。如果接口只有一种方法,它可以正常工作。如果它由多个方法组成,那么这些方法都不起作用。如何处理多种方法?

我们可以参考下面的例子

public interface I1()

    void show1();
    void show2();

那么主函数的结构会是什么来定义主函数本身的方法呢?

【问题讨论】:

你说的是functional interfaces吗?将所有其他方法设为default 如果我们不设置任何访问说明符,不应该是默认的吗? 接口方法是自动公开的。如果你不将它们设为默认,它们就不是默认的,而是抽象的。 @SoumyaKantiNaskar,默认情况下,接口方法有public abstract修饰符。 default 表示方法必须实现 我至少会链接到这个:***.com/questions/25299653/…(可能会认为它是重复的,但我不确定......) 【参考方案1】:

如 Eran 所说,Lambda 表达式仅可用于功能接口,但如果您确实需要接口中的多个方法,您可以将修饰符更改为 defaultstatic 并在必要时在实现它们的类中覆盖它们.

public class Test 
    public static void main(String[] args) 
        I1 i1 = () -> System.out.println(); // NOT LEGAL
        I2 i2 = () -> System.out.println(); // TOTALLY LEGAL
        I3 i3 = () -> System.out.println(); // TOTALLY LEGAL
    


interface I1 
    void show1();
    void show2();


interface I2 
    void show1();
    default void show2() 


interface I3 
    void show1();
    static void show2 () 


继承

你不应该忘记继承的方法。

这里I2继承了show1show2,因此不能作为函数接口。

public class Test 
    public static void main(String[] args) 
        I1 i1 = () -> System.out.println(); // NOT LEGAL BUT WE SAW IT EARLIER
        I2 i2 = () -> System.out.println(); // NOT LEGAL
    


interface I1 
    void show1();
    void show2();


interface I2 extends I1 
    void show3();


注释

为了确保你的接口是函数式接口,你可以添加如下注解@FunctionalInterface

@FunctionalInterface <------- COMPILATION ERROR : Invalid '@FunctionalInterface' annotation; I1 is not a functional interface
interface I1 
    void show1();
    void show2();


@FunctionalInterface
interface I2 
    void show3();

【讨论】:

注意I2 可以扩展I1 +1 @PeterLawrey 谢谢,我加了一点解释 Peter :) 您的继承示例也不会为 i 编译。 @eis 谢谢。已编辑。【参考方案2】:

Lambda 表达式只能用于实现函数式接口,即具有单个抽象方法的接口。具有两个抽象方法的接口不能由 lambda 表达式实现。

【讨论】:

您还必须将@FunctionalInterface 注解添加到接口(@98​​7654321@),编译器会检查接口中是否只有一个方法。 那么有没有其他替代方法可以像在 Lambda 表达式中一样删除样板代码? @MartinKrüger 您可以添加该注释,但您不必这样做。编译器会将满足函数式接口定义的任何接口视为函数式接口,无论接口声明中是否存在 FunctionalInterface 注释 @MartinKrüger 您没有添加@FunctionalInterface 注释来将接口用作lambda。虽然它有助于作为一个标记来表明这将只有一个抽象方法。 @SoumyaKantiNaskar 除非您为界面中的所有方法提供默认实现,但其中一个除外。【参考方案3】:

我一般是直接在接口中创建静态工厂方法:

public inteface I1 
    void show1();
    void show2();

    public static I1 of(Runnable show1, Runnable show2) 
        return new I1() 
            void show1()  show1.run(); 
            void show2()  show2.run(); 
        ;
    

用法:

I1 i1 = I1.of(() -> System.out.println("show1"), () -> System.out.println("show2"));

【讨论】:

为什么是静态工厂而不是构造函数? @Nikolas interface 的构造函数? 用于接口实现。【参考方案4】:

你总是可以使用合成:

public inteface I1 
    void show1();
    void show2();


public class I1Adapter 
    private final Runnable r1,r2;
    public I1Adapter(Runnable r1, Runnable r2) this.r1=r1; this.r2=r2;
    public void show1() r1.run();
    public void show2() r2.run();
    public static I1Adapter compose(Runnable r1, Runnable r2) 
        return new I1Adapter(r1,r2);
    

不可以(使用静态导入):

I1 i1 = compose(()->foo(), ()->bar());

【讨论】:

以上是关于通过 lambda 表达式实现具有两个抽象方法的接口的主要内容,如果未能解决你的问题,请参考以下文章

为什么Comparator接口有两个抽象方法compare和equals,却可以用Lambda

Lambda表达式

Lambda表达式

Lambda如何使用?

JavaSE-22.1.2Lambda表达式练习:无参无返回值抽象方法

JavaSE-22.1.3Lambda表达式练习:有参无返回值抽象方法