欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JEP 277“增强弃用”非常好。 但这是一个更好的选择

程序员文章站 2022-07-15 12:17:43
...

维护API很难。

我们正在维护非常复杂的jOOQ API。 但是就语义版本而言,我们遵循相对宽松的规则

当您阅读Brian Goetz和其他人关于在JDK中保持向后兼容性的评论时,我只能对他们的工作表示敬意。 显然,我们都希望最终移除VectorStackHashtable类的东西,但是在collection API周围存在与向后兼容相关的边缘情况,普通凡人不会想到。 例如: Java集合为什么不删除通用方法?

更好的弃用

JEP 277“增强弃用”非常好。 但这是一个更好的选择

Stuart Marks又名Dr Deprecator

使用Java 9,Jigsaw和模块化,这些新功能的主要驱动目标之一是能够“切断” JDK的各个部分,并在以后的发行版中轻轻地弃用并删除它们。 作为此改进的一部分, Stuart Marks AKA Deprecator博士建议了JEP 277:“增强的弃用”

这样做的目的是通过一些附加信息来增强@Deprecated批注,例如:

  • 不确定的 该API已被弃用,没有给出任何理由。 这是默认值; 今天隐含弃用的所有内容都有一个不赞成使用的弃用原因。
  • 谴责 该API已指定在将来的JDK版本中删除。 请注意,此处使用的“已谴责”一词在意欲拆除的结构的意义上使用。 该术语并不意味着暗示任何道德谴责。
  • 危险的 使用此API可能导致数据丢失,死锁,安全漏洞,错误结果或JVM完整性丢失。
  • 过时的 不再需要此API,应删除用法。 不存在替代API。 请注意,OBSOLETE API可能会或可能不会标记为CONDEMNED。
  • 放弃 该API已被较新的API取代,用法应从该API迁移到较新的API。 请注意,SUPERSEDED API可能会或可能不会被标记为CONDEMNED。
  • 已取消 调用无效或将无条件引发异常。
  • 实验 该API并不是规范的稳定部分,它可能会不兼容地更改或随时消失。

在弃用东西时,能够传达弃用的意图很重要。 也可以通过@deprecated Javadoc标记来实现,该标记可以生成任何类型的文本。

另一种更好的解决方案

上述主张存在以下问题:

  • 它是不可扩展的 对于JDK库设计人员来说,以上内容可能就足够了,但是作为第三方API提供程序的我们将希望枚举中包含更多元素,而不是CONDEMNED,DANGEROUS等。
  • 仍然没有纯文本信息 由于我们仍无法正式向注释提供任何可澄清的文本,例如为什么某事物“危险”的动机,因此该注释与Javadoc标记之间仍然存在冗余。
  • “不推荐使用”是错误的 将UNIMPLEMENTED或EXPERIMENTAL标记为“已弃用”的想法表明了该JEP的变通方法性质,它试图在现有名称中增加一些新功能。

我感到JEP太害怕触摸太多部分了。 但是,将有一个非常简单的替代方案,它对每个人都好得多:

public @interface Warning {
    String name() default "warning";
    String description() default "";
}

无需将可能的警告类型的数量限制为有限的常量列表。 相反,我们可以使用@Warning注释,该注释可以包含任何字符串!

当然,JDK可以具有一组众所周知的字符串值,例如:

public interface ResultSet {

    @Deprecated
    @Warning(name="OBSOLETE")
    InputStream getUnicodeStream(int columnIndex);

}

要么…

public interface Collection<E> {

    @Warning(name="OPTIONAL")
    boolean remove(Object o);
}

注意,虽然实际上不赞成使用JDBC的ResultSet.getUnicodeStream() ,但我们也可以向Collection.remove()方法添加提示,该方法仅适用于Collection类型,而不适用于其许多子类型。

现在,使用这种方法的有趣之处在于,我们还可以增强有用的@SuppressWarnings批注,因为有时,我们只是知道KnowWhatWeAreDoing™,例如在编写类似以下内容时:

Collection<Integer> collection = new ArrayList<>();

// Compiler!! Stop bitching
@SuppressWarnings("OPTIONAL")
boolean ok = collection.remove(1);

这种方法可以一次性解决许多问题:

  • JDK维护人员拥有他们想要的。 轻度弃用JDK的好工具
  • 关于 @SuppressWarnings可能发生的事情的记录不完整的混乱最终将变得更加干净和正式
  • 我们可以根据各种用例向用户发出大量自定义警告
  • 用户可以在非常细微的级别上使警告静音

例如: jOOQ的动机是消除DSL equal()方法与不幸的Object.equals()方法之间的歧义:

public interface Field<T> {

   /**
     * <code>this = value</code>.
     */
    Condition equal(T value);

    /**
     * <strong>Watch out! This is 
     * {@link Object#equals(Object)}, 
     * not a jOOQ DSL feature!</strong>
     */
    @Override
    @Warning(
        name = "ACCIDENTAL_EQUALS",
        description = "Did you mean Field.equal?"
    )
    boolean equals(Object other);
}

结论

毫无疑问,JEP 277很有用。 但是它的范围也非常有限(可能不会进一步延迟Jigsaw吗?)但是,我希望JDK维护人员可以更彻底地处理生成此类编译器警告的主题。 这是DoTheRightThing™的绝佳机会

我认为上述“规范”并不完整。 这只是一个粗略的主意。 但是我曾希望作为API设计人员多次尝试这种机制。 为了向用户提供有关潜在的API滥用的提示,他们可以通过以下方式将其静音:

  • @SuppressWarnings ,直接在代码中。
  • 易于实现IDE设置。 对于Eclipse,NetBeans和IntelliJ来说,对这些东西实施自定义警告处理将非常简单。

一旦有了@Warning批注,我们也许可以最后淘汰不那么有用的@Deprecated

@Warning(name = "OBSOLETE")
public @interface Deprecated {
}

翻译自: https://www.javacodegeeks.com/2015/12/jep-277-enhanced-deprecation-nice-heres-much-better-alternative.html