【问题标题】:Lambda can only be used with functional interface?Lambda 只能与函数式接口一起使用?
【发布时间】:2014-07-04 03:17:27
【问题描述】:

我这样做了:

public class LambdaConflict
{
    public static void main(String args[]){
        //*
        System.out.println(LambdaConflict.get(
            (str) -> "Hello World!! By ME?"
        ));
        /*/
        System.out.println(LambdaConflict.get(new Intf<String> (){
            @Override public String get1(String str){
                return "Hello World!! By get1 " + str;
            }
        }));
        /*****/
    }

    public static String get(Intf<String> i, boolean b){
        return i.get1("from 1");
    }
}

interface Intf<T>
{
    public T get1(T arg1);

    public T get2(T arg1);
}

并得到这个异常:

不兼容的类型:Intf 不是函数式接口 在接口 Intf 中找到多个非覆盖抽象方法 注意:一些消息已被简化;使用 -Xdiags:verbose 重新编译以获得 全输出 1 个错误

有什么情况不能用 lambda 代替匿名类吗?

【问题讨论】:

  • 你说的克服是什么意思?你了解错误吗?
  • 1) 功能接口必须只有一种方法。 2)它们必须被注释@FunctionalInterface
  • 功能接口也称为SAM类型(单一抽象方法类型)。因此,您的函数式接口中只能有一个抽象方法。
  • @RichardTingle:我认为第 2 点无效。它们可以被注释,但不是必需的。
  • @RichardTingle:关于注释的要点。这不会使现有的接口(如Runnable)失效吗?

标签: java lambda java-8 functional-interface


【解决方案1】:

没有。没有办法“克服”这一点。一个函数式接口必须只有一个抽象方法。你的界面有两个:

interface Intf<T> {
    public T get1(T arg1);
    public T get2(T arg1);
}

注意:您不需要像 cmets 中提到的那样注释您的界面。但是,如果您的接口不是有效的功能接口,您可以使用@FunctionalInterface 注释来获取编译时错误。因此,它为您的代码带来了更多的安全性。

有关更多信息,请参阅例如http://java.dzone.com/articles/introduction-functional-1

【讨论】:

  • 感谢@FunctionalInterface 的提示!我忘了它有特殊的属性。此外,我发现从 Oracle 升级到最新的 JDK8 补丁也有助于改善错误消息。旧版本的 JDK8 有时可能允许上面的代码编译,但在运行时会出现 java.lang.AbstractMethodError 失败。较新的版本将在编译时拒绝。
【解决方案2】:

仅供参考和丰富已经给出的答案:

根据JSR-335: Lambda Expressions for the Java Programming Language,在 Lambda 规范 A 部分:功能接口部分中它说:

函数式接口是只有一个抽象的接口 方法(除了 Object 的方法),因此表示一个 单一功能合约。 (在某些情况下,这种“单一”方法可能 采用多个具有覆盖等效的抽象方法的形式 从超级接口继承的签名;在这种情况下,继承 方法在逻辑上表示单个方法。)

因此,您需要为您的一种方法提供默认实现,或者将您的一种方法放在不同的接口中。

【讨论】:

    【解决方案3】:

    想一想:

    • 编译器应该如何知道您是要覆盖get1 还是get2

    • 如果只覆盖get1get2 的实现会是什么?即使您注释掉的代码也不起作用,因为您没有实现get2...

    这种限制是有原因的...

    【讨论】:

      【解决方案4】:

      正如@Thomas-Uhrig 所说,函数式接口只能有一种方法

      解决这个问题的方法,主要是因为您从不使用public T get2(T arg1);,将Intf&lt;T&gt; 接口更改为:

      @FunctionalInterface
      interface Intf<T>
      {
          public T get1(T arg1);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-10-27
        • 1970-01-01
        • 2016-05-20
        • 2021-06-29
        • 1970-01-01
        • 1970-01-01
        • 2014-11-04
        • 1970-01-01
        相关资源
        最近更新 更多