Java 8默认方法作为特征:安全吗?

you*_*uri 115 java traits java-8 default-method

在Java 8中使用默认方法作为穷人的特征是一种安全的做法吗?

一些人声称如果你只是为了它而使用它们可能会让熊猫感到悲伤,因为它很酷,但这不是我的意图.还经常提醒的是,引入了默认方法来支持API演变和向后兼容性,这是事实,但这并不会使它们错误或扭曲以将它们用作特征本身.

我有以下实际用例:

public interface Loggable {
    default Logger logger() {
        return LoggerFactory.getLogger(this.getClass());
    }
}
Run Code Online (Sandbox Code Playgroud)

或许,定义一个PeriodTrait:

public interface PeriodeTrait {
    Date getStartDate();
    Date getEndDate();
    default isValid(Date atDate) {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

无可否认,可以使用组合(甚至是辅助类),但它看起来更冗长,更混乱,并且不允许从多态性中受益.

那么,使用默认方法作为基本特征是否可行/安全,还是应该担心不可预见的副作用?

关于SO的几个问题与Java vs Scala特征有关; 这不是重点.我也不仅仅是在征求意见.相反,我正在寻找一个权威的答案或至少是现场洞察力:如果你在公司项目中使用默认方法作为特征,那么它是否真的是一个时间炸弹?

Bri*_*etz 119

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

讽刺的答案:告诉我的性格是什么意思,也许我会给你一个更好的答案:)

严肃地说,"特质"一词没有明确定义.许多Java开发人员最熟悉特征,因为它们在Scala中表达,但Scala远非第一种具有特征的语言,无论是名称还是有效.

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

同样,在Scala中,特征是通过线性化组成的; 如果类A延伸性状XY,然后的顺序XY在混合确定之间的冲突如何XY得到解决.在Java中,这种线性化机制不存在(它被部分拒绝,因为它太"非类似Java".)

将默认方法添加到接口的近似原因是支持接口演进,但我们很清楚我们已经超越了这一点.你是否认为这是"界面进化++"或"特征 - "是一个个人解释的问题.所以,回答你关于安全性的问题......只要你坚持机制实际支持的内容,而不是试图将它扩展到它不支持的东西,你应该没问题.

一个关键的设计目标是,从接口客户端的角度来看,默认方法应该与"常规"接口方法无法区分.因此,方法的默认值仅对接口的设计者实现者有意义.

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

  • 界面演变.在这里,我们向现有接口添加一个新方法,该接口在该接口上的现有方法方面具有合理的默认实现.一个例子是将forEach方法添加到Collection,其中默认实现是根据iterator()方法编写的.

  • "可选"方法.在这里,接口的设计者说"如果他们愿意接受需要的功能限制,那么实现者就不需要实现这种方法".例如,Iterator.remove给出了抛出的默认值UnsupportedOperationException; 由于绝大多数实现Iterator都有此行为,因此默认情况下此方法基本上是可选的.(如果行为AbstractCollection表示为默认值Collection,我们可能会对mutative方法执行相同的操作.)

  • 方便的方法.这些方法严格来说是为了方便,通常也是根据类中的非默认方法实现的.logger()您的第一个示例中的方法是对此的合理说明.

  • 组合子.这些是基于当前实例实例化接口的新实例的组合方法.例如,方法Predicate.and()或是Comparator.thenComparing()组合子的例子.

如果您提供了一个默认实现,那么您还应该为默认实现提供一些规范(在JDK中,我们使用@implSpecjavadoc标记)以帮助实现者理解他们是否要覆盖该方法.一些默认值,如方便方法和组合器,几乎从不被覆盖; 其他人,如可选方法,经常被覆盖.您需要提供有关默认承诺要做的足够的规范(不仅仅是文档),因此实现者可以做出明智的决定,决定是否需要覆盖它.

  • 感谢Brian这个全面的答案.现在我可以使用轻松的默认方法.读者:Brian Goetz关于界面演变和默认方法的更多信息可以在[NightHacking Worldwide Lambdas](http://youtu.be/Rkd166qA6WI?t=18m34s)中找到. (9认同)
  • 谢谢@brian-goetz。从你所说的来看,我认为 Java 的默认方法更接近 Ducasse 等人论文 (http://scg.unibe.ch/archive/papers/Duca06bTOPLASTraits.pdf) 中定义的传统特征的概念。Scala“特质”对我来说根本不像特质,因为它们有状态,在其组合中使用线性化,而且它们似乎也隐式解决了方法冲突 - 而这些都是传统特质所不具备的有。事实上,我想说 Scala 特征更像是 mixin,而不是特征。你怎么认为?PS:我从来没有用Scala 编写过代码。 (2认同)
  • @LahiruChandima 喜欢`MouseListener`?就这种 API 风格的意义而言,这适合“可选方法”桶。确保清楚地记录可选性! (2认同)