【问题标题】:Can @FunctionalInterfaces have default methods?@FunctionalInterfaces 可以有默认方法吗?
【发布时间】:2015-07-21 19:16:54
【问题描述】:

为什么我不能使用默认方法实现创建@FunctionalInterface

@FunctionalInterface
public interface MyInterface {
    default boolean authorize(String value) {
        return true;
    }
}

【问题讨论】:

    标签: java java-8


    【解决方案1】:

    您可以在 functional interface 中使用默认方法,但它的合同要求您提供一个抽象方法(或 SAM)。由于默认方法有一个实现,所以它不是抽象的。

    从概念上讲,函数式接口只有一个抽象方法。 由于默认方法有一个实现,它们不是抽象的。

    如果一个类型被这个注解类型注解,编译器是 需要生成错误消息,除非:

    该类型是接口类型而不是注解类型、枚举或 类。

    带注释的类型满足函数式的要求 界面。

    这里不满足函数式接口的要求,需要提供一个抽象方法。例如:

    @FunctionalInterface
    interface MyInterface {
    
        boolean authorize(int val);
        
        default boolean authorize(String value) {
            return true;
        }
    }
    

    请注意,如果您声明一个抽象方法覆盖了 Object 类中的公共方法之一,则它不计算在内,因为此接口的任何实现都将至少通过 Object 的类来实现这些方法。例如:

    @FunctionalInterface
    interface MyInterface {
    
        default boolean authorize(String value) {
            return true;
        }
    
        boolean equals(Object o);
    }
    

    不编译。

    【讨论】:

    • 最后一句话很误导人。您可能是指“其签名与java.lang.Object 中声明的方法匹配的抽象方法”。重要的一点是,具体类中的 声明 具有优先权,即使子类使用 abstract 方法覆盖它也是如此。非interface 类的abstract 方法仍然优先于interface 方法,即使后者不是abstract
    • @Holger 是的,这就是我的意思。我更新了它以使其更清晰。
    • @Holger,在我看来,java.lang.Object 就像一个带有一些 default 方法的接口
    • @mjalil 除了default 方法不能是protected 也不能是final。而且,正如已经说过的,来自像Object 这样的具体类的方法优先于接口方法。
    【解决方案2】:

    功能接口是一个interface,具有一个抽象方法。定义功能接口的全部目的是通过 lambda 表达式实现单个抽象方法,这将有效地覆盖该方法,这使得为其提供 default 实现毫无意义。

    拥有一个完全由default 方法组成的interface 会引发多个问题。当存在多个 default 方法时,编译器无法为 lambda 表达式决定实现哪个方法,并且存在完全由 default 方法组成的 interface 不是 @987654330 的语义问题@。您无法实例化此默认行为,因为您无法实例化 interfaces 并且强制程序员创建具体类只是为了调用默认行为,由于接口是无状态的,因此可以由单例提供:

    @FunctionalInterface
    public interface MyInterface {
        static MyInterface DEFAULT = s->true;
        boolean authorize(String value);
    }
    

    请注意,如果需要,您可以让接口扩展功能接口并提供默认方法。尽管如此,如果这导致创建一个没有抽象方法的interface,我会质疑这个设计。您可以与discussion about marker interfaces with default methods 进行比较。如果子接口与函数接口有不同的抽象方法,那就另当别论了。这可能有真正的用例,但这些子接口也将说明为什么它们不应该与函数基 interface 混合,因为 lambda 表达式将始终实现 abstract 方法。

    【讨论】:

    • default 函数式接口中的方法并非毫无意义。它can be used 处理非抛出接口的检查异常,例如Supplier
    • @Ivan 你应该在评论之前尝试正确阅读。没有人说默认方法毫无意义。 only 默认方法是没有意义的。您应该首先阅读并理解问题,因为答案是在特定上下文中给出的。
    【解决方案3】:

    那是因为@FunctionalInterface 可以有默认方法,只要你想就可以。例如,考虑java.util.Function 接口。它包含两个默认方法:composeandThen。但是应该只有一种非默认方法。否则编译器怎么知道你的哪些默认方法应该映射到 lambda?

    【讨论】:

      【解决方案4】:

      我只是想再补充几点。

      1. 我们可以在 FuntionalInterface 中拥有任意数量的 Abstract 方法。

      2. 我们还可以在 FuntionalInterface 中拥有任意数量的 Static 方法。

      3. 我们也可以声明一个抽象方法,覆盖对象类中的一个公共方法,但这个功能接口中还必须有一些其他自定义抽象方法,如下面的代码所示

        @FunctionalInterface 公共接口 SAM { 公共无效 helloSam();

            default void xyz() {
                System.out.println("xyz");
            }
        
            static void abc() {
                System.out.println("abc");
            }
        
            static void abc1() {
                System.out.println("abc1");
            }
        
            default void xyz1() {
                System.out.println("xyz1");
            }
        
             boolean equals(Object o);
        }
        

      【讨论】:

      • 使用这些方法会增加一些价值或解决一些问题吗?这不符合函数式接口的目的,即促进 lambda 表达式,不是吗?
      • FunctionalInterface 中只能有一个 Abstract 方法。第 1 点具有误导性
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-01
      • 2019-04-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多