21.2 Java 9的模块系统
Java 8引入了很多新变化,无论是新特性(比如接口的Lambda表达式和默认方法),还是原生API中强大的新类,比如Stream和CompletableFuture,都让人眼前一亮。Java 9并没有增加新的语言特性,它主要的变化是对Java 8发起的工作做进一步的改善,增加了一些新方法,比如流的takeWhile和dropWhile、CompletableFuture的completeOnTimeout。实际上,Java 9的重点是引入了新的模块系统。除了新的module-info.java文件,这种新的系统对语言没有任何影响,然而它从架构的角度改进了你设计和实现应用的方式,清晰地界定了各个子部分的边界,并定义了它们之间交互的方式。
不幸的是,相对任何其他的Java发布版本,Java 9对后向兼容性的损害也是最大的(你可以尝试用Java 9编译一个大型的Java 8项目)。不过,考虑到模块化所带来的好处,这种代价也是值得的。引入这样的变化,一个重要的原因是我们希望能有更好、更严格的跨包的封装性。实际上,Java的可见性描述符设计之初其目的是为了定义方法和类的封装,完全没有考虑跨包的封装,跨包它只有一种可见性可能,那就是: public。这种缺失让我们很难对系统进行恰当的模块化,尤其是如何声明模块的哪一部分允许公共访问,哪一部分是实现的细节,不应该直接暴露给其他模块和应用。
第二个原因,也是由包与包之间很弱的封装导致的直接结果。不采用模块系统,我们无法避免暴露运行于同一环境中安全相关的方法。恶意代码可能直接访问你模块的关键部分,直接绕开它所有的安全检查。
最后,新的Java模块系统可以帮助将Java运行时切分成更细粒度的部分,你可以只使用你应用需要的部分。如果你的一个新Java项目需要使用CORBA,然而,由此你需要在你所有的应用中包含该库,这应该也不是你所期望的吧。虽然这种行为的影响对传统计算设备而言几乎可以忽略不记 ,但对嵌入式设备或者你的Java应用运行于容器环境的场景(这种场景正越来越普遍)而言,其影响就非常重大了。换句话说,借助于Java模块系统,我们才有机会在物联网应用和云端使用Java运行时。
正如第14章中所讨论的,Java模块系统通过语言层面的机制,对你的系统及Java运行时进行模块化,解决了这些问题。Java模块系统的优势如下。
- 可靠的配置——通过显式声明模块的依赖性,错误可以在很早的时候,就借由编译检测到,而不必等到运行时发生了依赖缺失、依赖冲突,或者循环依赖才发现。
- 严格的封装——Java模块系统可以设置只导出某几个包,对模块的公有访问、每个模块的访问边界以及内部实现进行区分。
- 改进的安全性——由于用户无法随心所欲地调用模块的组成部分,因此攻击者想要攻破由模块系统实现的安全控制将更加困难。
- 更好的性能——如果一个类只能被有限的组件访问,而不是任何类都能在运行时加载它,那么对这样的类进行的很多优化都会更加有效。
- 扩展性——Java模块系统可以将Java SE平台解构成更细粒度的组成部分,你可以选择只执行运行你的应用所需要的特性。
一言以蔽之,模块化是一个复杂的话题,Java 9不太可能由于提供了这个特性就像Java 8提供了Lambda那样获得快速的推广。然而,我们相信,长远而言,你在你应用程序模块化方面的投入,一定会在程序的可维护性上得到收获和回报。
至此,我们已经总结了本书介绍的关于Java 8和Java 9的核心概念。接下来的内容,会介绍Java 9之后,Java语言可能有哪些特性提升以及新功能。
