我相信我是在 1997 年开始使用 Java 的,就在 Java 1.1 发布后不久。 从那时起,总的来说,我真的很喜欢用 Java 编程; 虽然我承认,现在我可能会写 Groovy 脚本,而不是 Java 中的“严肃代码”。
我之前用过 FORTRAN、PL/1、Pascal,最后是 C。 我发现 Java 有很多值得喜欢的地方。 Java 是我第一次真正上手 面向对象编程。 那时,我已经编程了大约 20 年,可以肯定地说,我对什么重要,什么不重要有一些自己的看法。
将调试作为关键语言特性
我真的讨厌浪费时间去追踪由于我的代码不小心迭代到数组末尾而导致的晦涩难懂的错误,尤其是在 IBM 大型机上用 FORTRAN 编程的时代。 另一个不时出现的微妙问题是,调用子程序时,传入一个四字节的整数参数,但子程序期望的是两个字节; 在小端架构上,这通常是一个良性错误,但在大端机器上,高两位字节的值通常(但不总是)为零。
在那个批处理环境中进行调试也很尴尬——仔细研究核心转储或插入打印语句,而打印语句本身可能会移动错误,甚至使其消失。
因此,我早期在 MTS 上,然后在使用相同的 MTS 编译器在 IBM OS/VS1 上使用 Pascal 的经验,让我的生活轻松了很多。 Pascal 的 强类型和静态类型 是一个很大的优势,而且我使用的每个 Pascal 编译器都会对数组边界和范围进行运行时检查,因此错误会在发生时被检测到。 20 世纪 80 年代初,当我们把大部分工作转移到 Unix 系统上时,移植 Pascal 代码是一项简单的任务。
找到合适的语法量
但是,尽管我喜欢 Pascal 的所有优点,我的代码还是冗长,而且语法似乎有一种稍微掩盖代码的倾向; 例如,使用
if … then begin … end else … end
而不是
if (…) { … } else { … }
在 C 和类似的语言中。 此外,有些事情在 Pascal 中很难做到,但在 C 中却容易得多。 但是,当我开始越来越多地使用 C 时,我发现自己遇到了和以前在 FORTRAN 中犯的同样的错误——例如,超出数组的末尾——这些错误不是在原始错误发生时被检测到,而是在程序执行后期通过其不利影响才被检测到。 幸运的是,我不再生活在批处理环境中,手头有很好的调试工具。 尽管如此,C 仍然给了我太多的自由,对我自己来说弊大于利。
当我发现 awk 时,我发现我有一个不错的 C 的对应物。 那时,我的很多工作都涉及转换字段数据和创建报告。 我发现我可以用 awk,再加上其他的 Unix 命令行工具,比如 sort、sed、cut、join、paste、comm 等等,做很多令人惊讶的事情。 本质上,这些工具给了我一些非常像文本文件的关系数据库管理器,这些文本文件具有面向列的结构,而这正是我们很多现场数据传入的方式。 或者,如果不是完全采用这种格式,大多数时候都可以从关系数据库或某种二进制格式将数据卸载到这种面向列的结构中。
awk 支持的字符串处理、正则表达式和 关联数组,以及 awk 的基本性质(它实际上是一个数据转换管道),非常符合我的需求。 当遇到二进制数据文件、复杂的数据结构和绝对的性能需求时,我仍然会回到 C; 但是,随着我越来越多地使用 awk,我发现 C 非常基本的字符串支持越来越令人沮丧。 随着时间的推移,我最终会越来越多地只在不得不使用 C 的时候才使用 C——并且可能会在其他时间过度使用 awk。
Java 是合适的抽象级别
然后 Java 就出现了。 从一开始它看起来就不错——一种相对简洁的语法,让人想起 C,或者至少比 Pascal 或任何其他早期的经验更像。 它是强类型的,因此很多编程错误会在编译时被捕获。 似乎不需要太多的面向对象学习就可以上手,这是一件好事,因为我当时对 OOP 设计模式 几乎一无所知。 但即使在早期,我也喜欢其简化的 继承模型 背后的想法。 (Java 允许单继承,并提供接口来丰富该范式。)
而且它似乎附带了一个丰富的功能库(“包含电池”的概念),这些功能库在适当的级别上工作,可以直接满足我的需求。 最后,我发现自己很快就喜欢上了将数据和行为组合在对象中的想法。 这似乎是一种显式控制数据之间交互的好方法——比巨大的参数列表或对全局变量的不受控制的访问要好得多。
从那以后,Java 已经成长为我编程工具箱中的瑞士军刀。 我仍然会偶尔用 awk 写东西,或者使用 Linux 命令行实用程序,比如 cut、sort 或 sed,当它们显然而且准确地是解决手头问题的直接方法时。 不过,我怀疑在过去的 20 年里我是否写过 50 行 C 代码; Java 已经完全取代了 C 以满足我的需求。
此外,Java 随着时间的推移一直在改进。 首先,它的性能变得更高。 而且它增加了一些非常有用的功能,比如 try with resources,它可以很好地清理处理文件 I/O 期间错误处理的冗长且有些混乱的代码; 或者 lambdas,它提供了声明函数并将其作为参数传递的能力,而不是旧的方法,后者需要创建类或接口来“托管”这些函数; 或者 streams,它将迭代行为封装在函数中,创建了一个高效的数据转换管道,以链式函数调用的形式实现。
Java 越来越好
许多语言设计师都在寻找彻底改善 Java 体验的方法。 对我来说,这些中的大多数目前还没有引起我太大的兴趣; 再次,这更多地反映了我的典型工作流程,(远)更少地反映了这些语言带来的特性。 但这些进化步骤中的一个已经成为我编程武器库中不可或缺的一部分:Groovy。 当我遇到需要一个小解决方案的小问题时,Groovy 已经成为我的首选解决方案。 此外,它与 Java 高度兼容。 对我来说,Groovy 填补了 Python 为许多其他人填补的同样的位置——它紧凑、DRY(不要重复自己)并且富有表现力(列表和字典具有完整的语言支持)。 我还使用了 Grails,它使用 Groovy 为非常高性能和有用的 Java Web 应用程序提供精简的 Web 框架。
但是 Java 仍然是开源的吗?
最近,对 OpenJDK 的日益增长的支持进一步提高了我对 Java 的舒适度。 许多公司以各种方式支持 OpenJDK,包括 AdoptOpenJDK、Amazon 和 Red Hat。 在我一个更大、更长期的项目中,我们使用 AdoptOpenJDK 来 在多个桌面平台上生成定制的运行时。
有比 Java 更好的语言吗? 我确信有,这取决于你的工作需求。 但我仍然是一个非常快乐的 Java 用户,我还没有看到任何威胁到把我拉走的东西。
8 条评论