就像其他语言一样,Java也会随着时间的推移而发展,Java代码的编写风格也是如此。然后是带有lambdas、Stream<T>和可选<T>的Java8,这些功能元素确实影响了我们编写Java代码的方式,但并没有发生革命,进化相当缓慢,为什么?
我认为有两个主要原因。
第一个原因是,即使是 Java 作者也不确定新的功能元素如何集成到现有的 Java 生态系统中。 要理解这种不确定性,阅读可选的 <T> Javadoc 就足够了:
API Note:Optional主要用于明确需要表示“无结果”并且使用null可能导致错误的方法返回类型。
API也显示了同样的情况:get()方法(可能抛出NPE)以及两个orelsetrow()方法的出现显然是对传统命令式Java编码风格的尊重。
第二个原因是,现有的Java代码,特别是库和框架,与函数方法不兼容——null和业务异常是惯用的Java代码。
快进到现在:Java17在几周前发布,Java11很快被广泛采用,取代了几年前无处不在的Java8。然而,我们的代码看起来几乎和7年前发布Java8时一样。
回过头来回答另一个重要问题可能是值得的:我们是否需要改变编写 Java 代码的方式? 长期以来,它为我们提供了足够好的服务。 我们有技能、指南、最佳实践和大量书籍来教我们如何以这种风格编写代码。 我们真的需要改变吗?
是的。我们需要提高开发性能,每一个框架、IDE、方法论、设计方法等都专注于提高软件的实现和部署速度(当然,有必要的质量标准)。然而,尽管如此,仍然没有明显的开发性能突破。
当然,有许多因素影响了软件交付的速度,比如开发性能。
在我看来,大多数提高开发性能的尝试都是假设编写更少的代码(通常更少的代码)自动意味着更好的性能。流行的库和框架,如Spring、Lombok和Faign,都试图减少代码量。即使是Kotlin,其创建也沉迷于简洁,而不是Java的“冗长”。历史确实多次证明这一假设是错误的(Perl和APL,也许是最值得注意的例子),然而,它仍然存在并推动了大部分工作。
任何开发人员都知道编写代码只是开发活动的一小部分。大多数时候我们都在读代码。阅读更少的代码是否更有效率?是的,但实际上,代码的数量和可读性几乎没有关系。同一代码的读写通常会有不同的“阻抗”,表现为精神负担。
“阻抗”中这种差异的最好例子可能是正则表达式。正则表达式非常紧凑,在大多数情况下非常容易编写,特别是使用无数专用工具。但是,阅读正则表达式通常是痛苦的,而且要花费更多的时间。为什么?原因是失去了背景。
当我们编写正则表达式时,我们知道上下文:我们想要匹配什么,应该考虑哪些情况,可能的输入是什么样子,等等。表达式本身是此上下文的压缩表示。但是当我们阅读它们时,上下文丢失了,精确地说,使用非常紧凑的语法压缩和压缩了上下文。试图从正则表达式中“解压缩”它是一项相当耗时的任务。在某些情况下,从头开始重写要比试图理解现有代码花费的时间少得多。
上面的例子给出了一个重要的提示:减少代码量只有在保持上下文的情况下才有意义。一旦减少代码会导致上下文丢失,它就开始起反作用并损害开发性能。
实用功能Java方式
实用功能Java是解决上述问题的一种尝试。虽然最初的目的只是通过将特殊状态编码为变量类型来保存上下文,但实际使用确实显示了所采取方法的许多其他好处:
1.大大减少了导航。
2.许多错误从运行时转移到编译时,这反过来提高了可靠性并减少了必要的测试数量。
3.删除了很大一部分样板文件,甚至是类型声明——更少的键入,更少的代码阅读,业务逻辑更少的技术细节。
4.明智地减少精神负担,需要记住与当前任务无关的技术问题。