Java 8 default methods as traits : safe?
在Java 8中使用默认方法作为穷人的男性版本是安全的做法吗?
有人说,如果你只是为了熊猫而使用它们,可能会让熊猫伤心,因为这很酷,但这不是我的意图。还经常提醒人们,引入了默认方法来支持API的演进和向后兼容性,这是正确的,但这并不意味着将它们本身用作特性是错误的或扭曲的。
我考虑了以下实际用例:
1 2 3 4 5 | public interface Loggable { default Logger logger() { return LoggerFactory.getLogger(this.getClass()); } } |
或者,定义一个
1 2 3 4 5 6 7 |
可以使用组合(甚至是助手类),但它看起来更加冗长和混乱,不允许从多态性中获益。
所以,使用默认方法作为基本特征是可以/安全的,还是我应该担心不可预见的副作用?
关于SO的几个问题与JavaS和Scala性状有关,这不是重点。我也不只是征求意见。相反,我在寻找一个权威性的答案,或者至少是实地观察:如果你在你的公司项目中使用了默认的方法作为特征,那么它是一个定时炸弹吗?
简短的回答是:如果安全使用它们是安全的。)
难听的回答:告诉我你所说的特质是什么意思,也许我会给你一个更好的答案:)
严肃地说,"特质"一词并没有很好地定义。许多Java开发人员最熟悉的是他们在Scala中表达的特性,但是斯卡拉远不是第一种具有特征的语言,无论是名字还是效果。
例如,在scala中,特征是有状态的(可以有
同样,在scala中,特征是通过线性化组成的;如果类
向接口添加默认方法的直接原因是为了支持接口演进,但是我们很清楚我们已经超越了这一点。不管你认为这是"界面进化++"还是"特性——"都是个人的解释。所以,为了回答你关于安全的问题…只要你坚持这个机制实际支持的东西,而不是一厢情愿地把它拉伸到它不支持的东西上,你就应该没事了。
一个关键的设计目标是,从接口的客户机的角度来看,默认方法应该与"常规"接口方法不可区分。因此,方法的默认性只对接口的设计者和实现者有意义。
以下是一些在设计目标范围内的用例:
界面演变。在这里,我们将向现有接口添加一个新方法,根据该接口上的现有方法,该方法具有合理的默认实现。一个例子是将
forEach 方法添加到Collection 中,其中默认实现是用iterator() 方法编写的。"可选"方法。在这里,接口的设计者说,"如果实现者愿意接受所需功能的限制,他们就不需要实现这个方法"。例如,
Iterator.remove 被赋予了一个缺省值,它抛出了UnsupportedOperationException ;由于Iterator 的绝大多数实现无论如何都具有这种行为,因此缺省值使得该方法本质上是可选的。(如果AbstractCollection 的行为表示为Collection 的默认值,我们可能会对突变方法做同样的操作。)方便方法。这些方法都是为了方便起见而严格执行的,同样也通常是根据类上的非默认方法来实现的。第一个示例中的
logger() 方法就是对此的合理说明。组合器。这些是基于当前实例实例化接口新实例的组合方法。例如,方法
Predicate.and() 或Comparator.thenComparing() 是组合器的例子。
如果您提供了一个默认的实现,那么您还应该提供一些默认的规范(在JDK中,我们使用