为什么我使用 Java

根据工作要求,可能存在比 Java 更好的语言。但我还没有看到任何能吸引我离开的东西。
208 位读者喜欢这篇文章。
Coffee beans

Pixabay. CC0.

我相信我是在 1997 年开始使用 Java 的,也就是 Java 1.1 问世后不久。 从那时起,总的来说,我真的很喜欢用 Java 编程; 尽管我承认现在,我更有可能编写 Groovy 脚本,而不是用 Java 编写“严肃的代码”。

我之前使用过 FORTRANPL/1Pascal,最后是 C,我发现 Java 有很多我喜欢的地方。Java 是我第一次重要的 面向对象编程 的实践经验。 那时,我已经编程了大约 20 年,并且可以肯定地说,我对什么重要,什么不重要有一些想法。

将调试作为关键语言特性

我真的很讨厌浪费时间来追踪那些由于我的代码不小心迭代到数组末尾而导致的模糊错误,尤其是在 IBM 大型机上用 FORTRAN 编程的那些日子。 另一个不时出现的微妙问题是用一个四字节的整数参数调用一个期望两个字节的子程序; 在小端架构上,这通常是一个良性错误,但在大端机器上,高两位字节的值通常(但并非总是)为零。

在批处理环境中进行调试也非常麻烦——仔细阅读核心转储或插入打印语句,这些语句本身可能会移动错误甚至使其消失。

因此,我早期使用 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——并且可能会在其余时间里过度使用 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 用户,并且我还没有看到任何威胁要将我带走的东西。

Chris Hermansen portrait Temuco Chile
自从 1978 年从不列颠哥伦比亚大学毕业以来,我很少没有某种计算机,自 2005 年以来,我一直是全职的 Linux 用户,从 1986 年到 2005 年,我一直是全职的 Solaris 和 SunOS 用户,在此之前,我一直是 UNIX System V 用户。

8 条评论

嗨,Chris! 令人印象深刻的简历和精彩的撰写。 感谢分享。

我建议您看看 Kotlin。 Kotlin Koans 是一种不错的入门方式,kts (Kotlin Scripts) 可能会取代您的 Groovy。 我真的很喜欢 Kotlin 非常强大的类型系统,同时与 Java 和 Groovy 非常相似(除了翻转的声明需要几天才能习惯)。

感谢您的评论,TWiStErRob。

我已经看过 Kotlin,但到目前为止,它还没有“与我交谈”。 也许有一天它会! Groovy 给我的感觉就像我一直希望 Python 给我的感觉一样,它引导我找到了 Grails,这让我对 Java 中所有美好的事物(例如 Spring)有了极大的赞赏。

无论如何,听起来你对 Kotlin 充满热情,因此我恳请你在 opensource.com 上撰写一篇或多篇文章来介绍它!

回复 作者:TWiStErRob (未验证)

很久以前我决定使用 php 和 html,因为您在浏览器中看不到源代码。 您只能看到结果。 我知道有很多方法可以防止这种情况,但作为一名新手 Web 程序员,这似乎是保护数据库数据安全的明智之举。

感谢您的评论,MJH。 据我所知,没有任何服务器端 Web 框架会在它们传递到浏览器的 HTML 中公开源代码(我说的是 PHP、Grails、Rails、Django...之类的东西)。 有些不需要源代码位于服务器上,而是执行字节码或本机代码。 例如,使用 Grails(我最熟悉),开发人员在开发机器上制作一个 .war 文件(它是 Java .class 文件以及 HTML、CSS、图像等),然后将其放在服务器上,应用程序服务器(例如 Tomcat)会解压缩它并提供服务。

回复 作者:MJH (未验证)

换句话说,你喜欢 Java 的理由和我喜欢 Ada 的理由是一样的。强类型和清晰的语法可以大大减少调试时间。此外,正式验证(使用 SPARK,Ada 的一个子集,与 Apache 无关)也有助于减少错误数量。

我只是更喜欢冗长的语法 "if .. then .. else .. end if",而不是基于 {} 的简洁语法。

感谢你的评论,Riccardo。就我的经验而言,Java 中的强静态类型是一个巨大的优势。我承认我们在喜欢简洁语法还是冗长语法方面存在分歧,我认为每个人都有自己的偏好。

对我而言,另一个产生巨大影响的是 Java 附带的所有好东西。例如,回到“美好的 Pascal 时代”,我可用的内存非常有限,我会通过构建中间查找数组来构建基于代码值的累加器,该数组将代码值(例如在 1-500 范围内)转换为“出现索引”(例如在 1-25 范围内)。然后,该出现索引将用于索引到指向堆结构的指针数组中,以进行累加。当然,这种类型的结构很容易不小心使用代码值而不是代码值的索引来查找指针数组,这会导致各种难以追踪的错误。

Awk 的关联数组,以及后来的 Java 的全套 HashMaps,完全避免了这类问题。当然,那时我的内存限制也不再那么成问题了。HashMap 与泛型提供的类型检查相结合,进一步有助于在编译时检测错误。

所以,由于我对 Ada 提供的“电池”类型不太熟悉,所以我不确定我们是否完全在同一页上!但无论如何,再次感谢你的来信,我邀请你考虑为 opensource.com 撰写一篇题为“我为什么使用 Ada”的文章!

回复 by rpr

我完全同意 - 我从 1996 年开始使用 Java,就再也没有回头,尽管我仍然有一些重要的 C++ 遗留代码库需要在极少数情况下进行维护。

新的语言不断涌现(告别 Ruby,希望那些认为在服务器端编写 JavaScript 是个好主意的人最终恢复理智)。

例如,其中一些语言会说:“我可以使用新语言 XYZ 完成令人难以置信的文本处理,而且我最终输入的字符比我在 Java 中实现相同的文本处理少 27%。”

对于这些说法,我说“做得好,给你一个慢动作的鼓掌:当我的开发者工作变成 97% 的时间都在输入代码并以奇怪的方式处理文本时,我会切换到你这种新颖的 XYZ 语言”。

我认为黑客倾向于将编码主要视为一种打字练习,因此节省击键似乎是一种提高生产力的方式。对他们来说,像类型安全这样需要为任何变量或参数输入类型规范的东西,只是令人讨厌的额外击键,没有任何实际好处 (LoL!)。

相比之下,我倾向于在开始输入任何内容之前,花费大量时间评估我正在构建的 OO 模型的不同选项——与那些我只是“拼凑出脑海中第一件事”的时候相比,花时间在白板上绘制多个实现方案可以节省数天、数月、数周的时间。

感谢你的评论,Golman。总的来说,我同意你的观点——在开发者的世界里,人们对闪亮的新事物有很多(也许太多了)赞赏。

话虽如此,我相信简洁明了是有价值的,尤其是在“不要重复自己”(DRY)原则中表达的。对我来说,Java 8 及以后的函数式接口对于代码维护人员和开发人员来说都是一个巨大的好处,仅仅是因为它减少了由于“此处”对象而产生的样板代码,这些对象的唯一目的是为单个函数提供实现。减少打字的明显事实有点顺便一提;真正的好处是代码更加紧凑和可读,并且当“what”没有被大量的“how”包围时,它会更加清晰可见。

在我看来,整个增强的集合是另一个很好的例子,其中内部迭代器和 lambda 表达式是非常好的东西。

我的 Java(和 Groovy)函数式技巧仍然非常基本。例如,如果我有一个输入文件,其中每一行包含几个不同的键值对,需要加载到几个不同的映射中,我不知道如何只处理一次就将所有映射作为函数式结果传递。也许存在这样的方法,只是我还没有见过;但是在 Groovy 中,我倾向于进行大多数此类工作,我发现自己声明了所有映射,然后使用“each”来迭代文件,并根据需要分配 map1[key1] = value1、map2[key2] = value2 等等。

100% 同意花时间在设计概念上。我发现现在白板的替代方法是使用 Groovy 进行原型设计。我不是一个非常有视觉感的人,所以缺乏图表并不会让我感到不安。在我确定一个似乎朝着良好方向发展的原型之前,我可能会制作多个原型;而且我经常使用原型设计作为测试相对性能的借口。当涉及到 SQL 时也是如此。但我怀疑这可能更多地表明什么对解决我发现自己正在解决的问题有效,而不是一般的规则。

无论如何,再次感谢你周到的评论。

回复 by Golman (未验证)

Creative Commons License本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。
© . All rights reserved.