【问题标题】:Should 'Comparable<T>' be a 'Functional interface'?'Comparable<T>' 应该是“功能接口”吗?
【发布时间】:2014-10-03 01:25:40
【问题描述】:

函数式接口的定义是“函数式接口是只有一个抽象方法的接口 (除了 Object 的方法),因此代表一个单一的函数合约。”

根据这个定义,Comparable&lt;T&gt; 绝对是一个函数式接口。

lambda 表达式的定义是“一个 lambda 表达式就像一个方法:它提供了形式参数的列表 和一个主体 - 一个表达式或块 - 用这些参数表示。”

对 lambda 表达式的求值会产生一个函数式接口的实例。

因此,lambda 表达式的目的是能够创建函数接口的实例,通过实现 功能接口的单一功能。 IE。允许使用单个函数创建实例。

让我们看看Comparable&lt;T&gt;,这个界面是设计成单一功能使用的吗? IE。它是为创建仅具有这个单一功能的实例而设计的吗?

Comparable&lt;T&gt; 的文档以“此接口对每个类的对象施加总排序”开头 实现它。这种排序被称为类的自然排序,类的 compareTo 方法被称为 to 作为它的自然比较方法。”

上面这句话清楚地表明Comparable&lt;T&gt; 并非旨在用作单个函数,而是始终 意味着由一个类实现,它的实例具有自然顺序,通过添加这个单一的函数。

这意味着它不是为使用 lambda 表达式创建的?

关键是我们不会有任何只是 Comparable 的对象,它意味着被实现并因此被使用 作为类的附加功能。

那么,Java 语言中有没有一种方法可以防止为 Comparable&lt;T&gt; 创建 lambda 表达式? 接口的设计者是否可以决定该接口是由一个类实现而不是由一个类实现的? 通过使用 lambda 表达式使用这种单一方法创建为实例?

仅仅因为一个接口碰巧有一个抽象方法,它不应该被认为是一个函数式接口。

也许,如果Java提供了NotFunctional这样的注解,那么编译器就可以检查出这个接口没有被使用 用于创建 lambda 表达式,例如。

@NotFunctional
public interface Comparable<T> { public int compareTo(T t); }

【问题讨论】:

  • interfaces 无法控制它们的实现方式。那么为什么要改变 lambda 的情况呢?

标签: java interface lambda java-8 functional-interface


【解决方案1】:

当需要具有单个抽象方法的接口实例时,可以使用 lambda 表达式。你写的,

仅仅因为一个接口碰巧有一个抽象方法,它不应该被认为是一个函数式接口。

这完全正确。拥有一个抽象方法是接口的一个 结构 属性,它使它有资格用 lambda 实现。然而,一个接口有意义还是语义是否适合用 lambda 实现是另一回事。后者是@FunctionalInterface 注解的目的。当它出现在接口上时,它表明 intent 该接口对于使用 lambda 实现是有用的。

值得注意的是,Comparable 接口缺少@FunctionalInterface 注释。

虽然使用 lambda 作为Comparable 实现可能是荒谬的,但似乎没有任何理由创建一种机制来防止这种情况发生。这样做似乎不会成为错误的来源,这将是开发这种机制的一个很好的理由。相比之下,@FunctionalInterface 注释旨在引导程序员朝正确的方向前进,而不是禁止一些可以说是错误但似乎并不真正有害的事情。

【讨论】:

  • 同意你的 cmets。如何从“API”向“API 用户”建议特定接口不打算用作“功能接口”,除非记录它。在这种情况下,@NotFunctional 之类的注释会很有用,编译器可以确保它不用作 lambda 表达式。让我知道这是否有意义。
  • @user2363727 文档可能是最好的。 lambda 是否合法 是语言的一部分,注释(大部分)不会影响程序构造的合法性。 @NotFunctional 之类的注释可能会产生警告,但在我看来它不会增加太多价值。我很难想象有人会如何尝试将 lambda 用于 Comparable,从而导致逻辑错误(而不是编译时错误)。有人可以尝试,但他们很快就会意识到这没有意义。所以让编译器以某种方式检查这一点似乎不值得。
  • '使用 lambda 作为 Comparable 实现是荒谬的' - 请问为什么它是荒谬的?
  • @Andrey 一个类实现了 Comparable 接口以允许将该类的一个实例与该类的另一个实例进行比较。比较通常使用这些实例中包含的状态(字段)来完成。由于 lambda 没有字段,很难想象 lambda 如何有用实现 Comparable,即使在技术上可以编写一个这样的实现。
  • @Karan 考虑Comparable&lt;String&gt; c = s -&gt; 0。它显然是一个 Comparable 并且它的实现是一个 lambda。但是,它不是一个很好的 Comparable:c.compareTo("x") 返回零,而 "x".compareTo(c) 甚至不会编译。 (如果你可以编译它,调用它会抛出 ClassCastException。)
【解决方案2】:

问题来自“方法”和“函数”之间的细微差别。

函数的输出值仅取决于输入到该函数的参数。

然而,方法的输出取决于输入到函数的参数,但也可能取决于对象的状态(实例变量)。

也就是说,任何函数都是方法,但并非所有方法都是函数。

例如,接口 Comparator 中的方法 compare 仅取决于其参数。但是Comparable接口中的compareTo方法依赖于要比较的对象的状态,所以需要在类中实现。

所以即使 Comparable 也有一个抽象方法,从语义上讲,它不应该被视为函数式接口。

【讨论】:

    【解决方案3】:

    没有任何机制可以防止天真地使用不打算成为功能接口的接口。 通过使用像@NotFunctional 这样的附加注解,它可以由一个显式声明 接口的设计者,它不应该用作 lambda。 并且默认如果没有指定注解,可以认为和@Functional一样好, 目前就是这样。

    【讨论】:

    • :) 聪明的答案,它不应该是 Java 8 API 中可用的注释。当我们定义/使用 @NonFunctional 接口的 lambda 表达式时,编译器应该给我们错误/警告?
    【解决方案4】:

    好吧,除了讨论之外,信息性注释 @FunctionalInterface 有多么有用(我很高兴 Java 8 不需要它用于 lambdas)。

    Comparable 通常是类型的属性,因此不适合用作函数式接口。它是explicitly described 作为自然排序并且不采用两个this/that 参数。所以这个属性使得任何方法都不太可能在 lambda 上运行(类似的参数适用于几乎所有 -able 接口)。

    因此,集合设计者为该任务使用了第二个接口:Comparator&lt;T&gt;,为此使用 lambda 实现它是一个非常自然的选择。

    【讨论】:

      猜你喜欢
      • 2012-03-01
      • 2019-10-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-17
      • 1970-01-01
      • 2011-04-21
      相关资源
      最近更新 更多