Java 8 默认方法作为特征 : safe?

标签 java java-8 traits default-method

使用 是否安全?默认方法作为特征的穷人版本 在 Java 8 中?

Some claim it may make pandas sad如果你只是为了它而使用它们,因为它很酷,但这不是我的意图。也经常有人提醒,默认方法是为了支持 API 演化和向后兼容而引入的,这是事实,但这并不意味着将它们用作特征本身是错误的或扭曲的。

我有 the following practical use case心里:

public interface Loggable {
    default Logger logger() {
        return LoggerFactory.getLogger(this.getClass());
    }
}

或者,定义一个 PeriodTrait :
public interface PeriodeTrait {
    Date getStartDate();
    Date getEndDate();
    default isValid(Date atDate) {
        ...
    }
}

诚然,可以使用组合(甚至是辅助类),但它似乎更加冗长和困惑,并且不允许从多态中受益。

所以,使用默认方法作为基本特征是否可以/安全 ,还是我应该担心无法预料的副作用?

Several questions在 SO 上与 Java 与 Scala 特征有关;这不是重点。我也不仅仅是征求意见。相反,我正在寻找权威的答案或至少是现场洞察力:如果您在公司项目中使用默认方法作为特征,结果是定时炸弹吗?

最佳答案

简短的回答是:如果你安全地使用它们是安全的:)

尖刻的回答:告诉我你所说的特征是什么意思,也许我会给你一个更好的答案:)

严肃地说,“特质”一词并没有明确定义。许多 Java 开发人员最熟悉 Scala 中表达的特征,但 Scala 远不是第一种具有特征的语言,无论是名称还是效果。

例如,在 Scala 中,traits 是有状态的(可以有 var 变量);在堡垒中,他们是纯粹的行为。 Java 的默认方法接口(interface)是无状态的;这是否意味着它们不是特征? (提示:这是一个棘手的问题。)

同样,在 Scala 中,特征是通过线性化组合而成的;如果类A扩展特性 XY ,那么X的顺序和 Y混入决定了X之间如何冲突和 Y得到解决。在 Java 中,这种线性化机制不存在(它被拒绝了,部分原因是它太“不像 Java”了。)

为接口(interface)添加默认方法的最直接原因是支持接口(interface)演化,但我们很清楚我们正在超越这一点。无论您认为这是“界面进化++”还是“特征--”,这都是个人解释的问题。因此,要回答您关于安全性的问题……只要您坚持该机制实际支持的内容,而不是一厢情愿地将其扩展到它不支持的内容,您应该没问题。

一个关键的设计目标是,从接口(interface)客户端的角度来看,默认方法应该与“常规”接口(interface)方法没有区别。因此,方法的默认值只对接口(interface)的设计者和实现者感兴趣。

以下是一些完全符合设计目标的用例:

  • 界面演变。在这里,我们向现有接口(interface)添加了一个新方法,就该接口(interface)上的现有方法而言,该方法具有合理的默认实现。一个例子是添加 forEach方法 Collection ,其中默认实现是根据 iterator() 编写的方法。
  • “可选”方法。在这里,接口(interface)的设计者说“如果实现者愿意忍受所带来的功能限制,他们就不需要实现这个方法”。例如,Iterator.remove给出了一个默认值,抛出 UnsupportedOperationException ;因为 Iterator 的绝大多数实现无论如何都有这种行为,默认情况下该方法本质上是可选的。 (如果来自 AbstractCollection 的行为被表达为 Collection 的默认值,我们可能对可变方法做同样的事情。)
  • 方便的方法。这些是严格为了方便起见的方法,通常也是根据类的非默认方法实现的。 logger()您的第一个示例中的方法是对此的合理说明。
  • 组合器。这些是基于当前实例实例化接口(interface)的新实例的组合方法。例如,方法 Predicate.and()Comparator.thenComparing()是组合子的例子。

  • 如果您提供默认实现,您还应该为默认提供一些规范(在 JDK 中,我们为此使用 @implSpec javadoc 标记)以帮助实现者了解他们是否要覆盖该方法。一些默认值,如便利方法和组合器,几乎从未被覆盖;其他的,比如可选的方法,经常被覆盖。您需要提供关于默认 promise 做什么的足够规范(不仅仅是文档),以便实现者可以就他们是否需要覆盖它做出明智的决定。

    关于Java 8 默认方法作为特征 : safe?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28681737/

    相关文章:

    java - 从 JAVA 中的字符串中提取 CSS 样式

    java - 为什么将方法作为 getOrDefault 的参数,该方法无论如何都会被调用?

    generics - 具有标记特征的Rust meta/复合结构

    Scala 特征和隐式转换混淆

    php - "Trait not found error"与trait的定义顺序和内容相关

    java - 使用 2 个 Java 类显示 1 个 XML 文件的信息

    java - 如何在命令行上指定 keystore 类型?

    java - play 2.0.2测试查询参数错误

    java - 在 Java 中,流相对于循环的优势是什么?

    java-8 - 映射到多个键的 Java 8 Stream "collect and group by"对象