如何改进代码废弃

Hi,我是阿昌,今天学习记录的是关于如何改进代码废弃

像所有的事物一样,公开接口也有生命周期。

要废弃那些被广泛使用的、或者还有人使用的公开接口,是一个非常痛苦的过程。

该怎么废弃一个公开接口,该怎么减少废弃接口的影响呢?

一、阅读案例

在 JDK 中,一个公开的接口,可能会因为多种多样的原因被废弃。

比如说,这个接口的设计是危险的,或者有了更新的、更好的替代接口。

不管是什么原因,废弃接口的使用者们都需要尽快迁移代码,转换到替代方案上来。

在 JDK 中,公开接口的废弃需要使用两种不同的机制,也就是“Deprecated” 注解(annotation)和“Deprecated”文档标记(JavaDoc tag)。

Deprecated 的注解会编译到类文件里,并且可以在运行时查验。

这就允许像 javac 这样的工具检测和标记已废弃接口的使用情况了。

Deprecated 文档标记用于描述废弃接口的文档中。

除了标记接口的废弃状态之外,一般情况下,还要描述废弃的原因和替代的方案。

下面的这段代码,就是使用 Java 注解和文档标记来废弃一个公开接口的例子。

public sealed abstract class Digest {/*** -- snipped** @deprecated This method is not performance friendly. Use*             {@link #digest(byte[], byte[]) instead.*/@Deprecatedpublic abstract byte[] digest(byte[] message);// snippedpublic void digest(byte[] message, byte[] digestValue) {// snipped}
}

如果一段程序使用了废弃接口,编译的时候,就会提出警告。

但是,有很多编译环境的配置,把编译警告看作是编译错误。

为了解决这样的问题,JDK 还提供了“消除使用废弃接口的编译警告”的选项。也就是 SuppressWarnings 注解

@SuppressWarnings("deprecation")
public static void main(String[] args) {try {Digest.of("SHA-256").digest("Hello, world!".getBytes());} catch (NoSuchAlgorithmException ex) {// ignore}
}

公开接口的废弃机制,是在 JDK 1.5 的时候发布的。

这种机制像一座设计者和使用者之间的沟通桥梁,减轻了双方定义或者使用废弃接口的痛苦。

遗憾的是,直到现在,公开接口的废弃,依然是一个复杂、痛苦的过程。

一个公开的接口,从声明废弃,到彻底删除是一个漫长的过程。

在 JDK 中,还存在着大量废弃了 20 多年都无法删除的公开接口。为什么删除废弃的公开接口这么困难呢?

如果从废弃机制本身的角度来思考,下面几个问题延迟了废弃接口使用者的迁移意愿和努力。

  • 第一个问题,也是最重要的问题,就是 SuppressWarnings 注解的使用。SuppressWarnings 注解的本意是消除编译警告,保持向后的编译兼容性。可是一旦编译警告消除,SuppressWarnings 注解也就抵消了 Deprecated 注解的功效。代码的维护者一旦使用了 SuppressWarnings 注解,就很难再有更合适的工具,让自己知道还在使用的废弃接口有哪些了。不知道,当然就不会有行动。
  • 第二个问题,就是废弃接口的使用者并不担心使用废弃接口。虽然我们都知道不应该使用废弃的接口,但是因为一些人认为没有紧急迁移的必要性,也不急着制定代码迁移的时间表,所以倾向于先使用 SuppressWarnings 注解把编译警告消除了,以后再说迁移的事情。然后,就掉入了第一个问题的陷阱。
  • 第三个问题,就是废弃接口的使用者并不知道接口废弃了多久。在接口使用者的眼里,废弃了十年,和废弃了一年的接口,没有什么区别。可是,在接口维护者的眼里,废弃了十年的接口,应该可以放心地删除了。然而,使用者并没有感知到这样的区别。没有感知,当然也就没有急迫感了。一旦一个接口被声明为废弃,它的问题也就再难进入接口维护者的任务列表里了。

这个接口的实现可能充满了风险和错误。于是局面就变成了,接口维护者难以删除废弃的接口,接口的使用者又不能获得必要的提示,这种情况实在有点尴尬。

二、改进的废弃

在 JDK 9 的接口废弃机制里有了重大的改进。第一个改进是添加了一个新的工具,jdeprscan

有了这个工具,就可以扫描编译好的 Java 类或者包,看看有没有使用废弃的接口了。即使代码使用了 SuppressWarnings 注解,jdeprscan 的结果也不受影响。

这个工具解决了在阅读案例里提到的第一个问题。

  • 如果使用第三方的类库,或者已经编译好的类库,发现对废弃接口的依赖关系很重要。如果将来废弃接口被删除,使用废弃接口的类库将不能正常运行。而 jdeprscan 允许我们在使用一个类库之前进行废弃依赖关系检查,提前做好风险的评估。

  • 第二个改进是给 Deprecated 注解增加了一个“forRemoval”的属性。如果这个属性设置为“true",那就表示这个废弃接口的删除已经提上日程了。两到三个版本之后,这个废弃的接口就会被删除。这样的改进,强调了代码迁移的紧急性,它给了使用者一个明确的提示。这个改进,解决了我们在阅读案例里提到的第二个问题。

  • 第三个改进是给 Deprecated 注解增加了一个“since”的属性。这个属性会说明这个接口是在哪一个版本废弃的。如果我们发现一个接口已经废弃了三年以上,就要考虑尽最大努力进行代码迁移了。这样的改进,给了废弃接口的使用者一个时间上的概念,也方便开发者安排代码迁移的时间表。这个改进,解决了在阅读案例里提到的第三个问题。

下面的这段代码,就是一个使用了这两种属性的例子。

public sealed abstract class Digest {/*** -- snipped** @deprecated This method is not performance friendly. Use*             {@link #digest(byte[], byte[]) instead.*/@Deprecated(since = "1.4", forRemoval = true)public abstract byte[] digest(byte[] message);// snippedpublic void digest(byte[] message, byte[] digestValue) {// snipped}
}

如果在 Deprecated 注解里新加入“forRemoval”属性,并且设置为“true",那么以前的 SuppressWarnings 就会失去效果。

要想消除掉编译警告,需要使用新的选项。

就像下面的例子这样。

@SuppressWarnings("removal")
public static void main(String[] args) {try {Digest.of("SHA-256").digest("Hello, world!".getBytes());} catch (NoSuchAlgorithmException ex) {// ignore}
}

当一个废弃接口的删除提上日程的时候,添加“forRemoval”属性让我们又有一次机会在代码编译的时候,重新审视还在使用的废弃接口了。

三、废弃三部曲

有了 JDK 9 的废弃改进,我们就能够看到接口废弃的一般过程了。

  • 第一步,废弃一个接口,标明废弃的版本号,并且描述替代方案;
  • 第二步,添加“forRemoval”属性,把删除的计划提上日程;
  • 第三步,删除废弃的接口。对于接口的使用者,应该尽量在第一步就做好代码的迁移;

如果我们不能在第一步完成迁移,当看到第二步的信号时,也要把代码迁移的工作提高优先级,以免影响后续的版本升级。

对于接口的维护者,我们需要尽量按照这个过程退役一个接口,给接口的使用者充分的时间和信息,让他们能够完成代码的迁移。

四、总结

要管理好废弃的接口。接口的废弃要遵守程序,有序推进;

代码的迁移要做好计划,尽快完成。

另外,要使用好 jdeprscan 这个新的工具。

在使用一个类库之前,要有意识地进行废弃依赖关系检查,提前做好代码风险的评估。

如果面试中聊到了接口废弃的问题,可以聊一聊接口废弃的三部曲,以及每一步应该使用的 Java 注解形式。


Day724. 如何改进代码废弃 -Java8后最重要新特性相关推荐

  1. Day719. 矢量运算 -Java8后最重要新特性

    矢量运算 Hi,阿昌来也,今天学习记录的是关于此时此刻还在预览阶段的矢量运算. Java 的矢量运算,我写这篇文章的时候还在孵化期,还没有发布预览版. 这个技术代表了 Java 语言发展的一个重要方向 ...

  2. Day716. 抛出异常是一个合适的选择吗? -Java8后最重要新特性

    抛出异常是一个合适的选择吗? Hi,我是阿昌,今天学习记录的是关于抛出异常是一个合适的选择吗? Java 的错误处理,算不上是特性.但是 Java 错误处理的缺陷和滥用,却一直是一个很有热度的话题. ...

  3. JAVA8后接口的新特性

    知识点一: 知识点二: 知识点三: 知识点四: 知识点五:

  4. java8 stream遍历_Java8新特性:Stream流详解

    1. Stream初体验 我们先来看看Java里面是怎么定义Stream的: A sequence of elements supporting sequential and parallel agg ...

  5. 【java基础】快速掌握 Java5、Java6、Java7、Java8、Java9 的新特性!!!

    1. 介绍 JAVA作为使用的主力语言,掌握下其历史发展也是有必要的.看看从JAVA5开始到现在的JAVA9有哪些变化.借此机会,也可以看看哪些特性我们是已经用到的,哪些是还没有用到的. 如果有程序猿 ...

  6. java8遍历数组_java8新特性,使用流遍历集合

    在这篇"Java 8新特性教程"系列文章中,我们会深入解释,并通过代码来展示,如何通过流来遍历集合,如何从集合和数组来创建流,以及怎么聚合流的值. 在之前的文章"遍历.过 ...

  7. Java8的十大新特性

    Java9预计将于今年9月份发布,这是否会是一次里程碑式的版本,我们拭目以待.今天,我们先来复习一下2014年发布的Java 8的十大新特性. Java 8可谓是自Java 5以来最具革命性的版本了, ...

  8. Java9都快发布了,Java8的十大新特性你了解多少呢?

    Java 9预计将于今年9月份发布,这是否会是一次里程碑式的版本,我们拭目以待.今天,我们先来复习一下2014年发布的Java 8的十大新特性. Java 8可谓是自Java 5以来最具革命性的版本了 ...

  9. Java8的一些常用新特性

    Java8新特性 回顾: 1 反射:是类的解剖技术,把类中各个元素使用对象封装.属性.方法.构造方法 2 Class 是反射的起源 ,每个类都是Class的对象,而且只有一个(1)通过对象getCla ...

最新文章

  1. aspose 换行写_aspose.word 换行符 aspose.words换行符
  2. HUST软工1506班第2周作业成绩公布
  3. C++:两个数组求最值、排序、合并
  4. oracle创建索引后sqlldr导入错误
  5. 2020年Tor Project的加密货币捐款增加23%达23万美元
  6. 九度OJ-1525 子串逆序打印
  7. php代码敲得很慢,thinkphp好慢 帮忙看看什么原因?已贴代码
  8. delphi制作上下开幕效果_显示产业国际盛会开幕,广州新型显示产值将突破2500亿...
  9. ASP.NET MVC 学习笔记(1)
  10. html左边图片右边文字_有了这些网站,不用PS也可以做出文字云效果
  11. 安装linux下显卡驱动
  12. python程序开发入门教程_史上最全Python快速入门教程,满满都是干货
  13. java odbc 驱动_Java java.sql.SQLException: [Microsoft][ODBC 驱动程序管理器] 未发现数据源名称并且未指定默认驱动程序...
  14. SiamRPN++论文阅读
  15. DES算法是对称算法吗,能否通过在线工具进行DES解密?
  16. 【夜深人静写代码】倍增算法学习记录
  17. WiFi大师小程序3.0.9独立版源码
  18. html.dropdownlist 样式,使用@ Html.DropDownList()添加要选择的css类
  19. 常见色域基础知识与色域转换公式(YUV/YCbCr/YIQ/RGB/R‘G‘B‘/CMYK)
  20. mysql 过滤微信昵称表情_微信昵称emoji表情的过滤

热门文章

  1. 结合CAP理论分析ElasticSearch的分布式实现方式
  2. 基于WebGL架构的3D可视化平台—粮仓3D场景
  3. python层次分析法一致性检验+权重计算
  4. erp故障处理流程图_完整ERP流程图
  5. 如何获取文件的后缀名?
  6. C语言程序设计第六章例题(数组)
  7. 浅谈软件和信息技术服务业发展规划与数字化转型方法(第一稿)
  8. 全球化手册|日本篇笔记
  9. Shell脚本中获取命令运行结果、特殊变量使用、条件判断等常用操作
  10. 7.2 - 在线教育平台系统