我相信我从 1997 年开始使用 Java,那时距离 Java 1.1 问世 不久。从那时起,总的来说,我非常喜欢用 Java 编程;虽然我承认现在,我可能更常写 Groovy 脚本,而不是用 Java 编写“严肃的代码”。
我来自 FORTRAN、PL/1、Pascal 和最后的 C 背景,我发现 Java 有很多我喜欢的地方。Java 是我第一次实际体验 面向对象编程。那时,我已经编程大约 20 年了,可以肯定地说,我对什么是重要的,什么是不重要的,有一些自己的看法。
将调试作为关键语言特性
我真的很讨厌浪费时间追踪由我的代码粗心大意地迭代超出数组末尾而导致的晦涩错误,尤其是在过去使用 FORTRAN 在 IBM 大型机上编程的日子里。另一个不时出现的微妙问题是用一个四字节的整数参数调用一个期望两个字节的子程序;在小端架构上,这通常是一个良性错误,但在大端机器上,高两位字节的值通常(但并非总是)为零。
在批处理环境中进行调试也很麻烦——仔细查看核心转储或插入打印语句,而打印语句本身可能会移动错误,甚至使其消失。
因此,我早期在使用 Pascal 的经验,首先是在 MTS 上,然后在 IBM OS/VS1 上使用相同的 MTS 编译器,使我的生活轻松了很多。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 期间处理错误处理的冗长且有些混乱的代码;或者 lambda 表达式,它提供了声明函数并将它们作为参数传递的能力,而不是旧方法,旧方法需要创建类或接口来“托管”这些函数;或者 stream,它将迭代行为封装在函数中,创建以链式函数调用形式体现的高效数据转换管道。
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 条评论