我为什么使用 Java

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

Pixabay. CC0.

我相信我是在 1997 年开始使用 Java 的,就在 Java 1.1 发布后不久。 从那时起,总的来说,我真的很喜欢用 Java 编程; 虽然我承认,现在我可能会写 Groovy 脚本,而不是 Java 中的“严肃代码”。

我之前用过 FORTRANPL/1Pascal,最后是 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 用户,我还没有看到任何威胁到把我拉走的东西。

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

8 条评论

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

我建议你看看 Kotlin。 Kotlin Koans 是一个不错的入门方式,kts(Kotlin 脚本)可能会取代你的 Groovy。 我非常喜欢 Kotlin 非常强大的类型系统,同时它又与 Java 和 Groovy 非常相似(除了反转的声明,需要几天才能适应)。

感谢你的评论,TWiStErRob。

我看过 Kotlin,但到目前为止它还没有“打动我”。 也许有一天它会! Groovy 感觉就像我一直希望 Python 感觉到的那样,它让我对 Grails 赞不绝口,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”的文章!

回复 ,作者是 rpr

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

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

其中一些语言说,例如,“我可以用新的 XYZ 语言进行这种令人难以置信的文本操作,并且我最终输入的字符比我在 Java 中实现相同的文本操作少 27%。”

为了回应这些说法,我说“做得好,这是你的慢速高尔夫鼓掌:当我的开发人员工作变成 97% 的时间都花在输入代码和以奇怪的方式操作文本时,我会切换到你这个新的、当月流行的 XYZ 语言”。

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

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

感谢您的评论,Golman。总的来说,我同意你的观点 - 在开发人员的世界里,人们对闪亮的新事物有很多(可能太多)的赞赏。

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

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

我的 Java(和 Groovy)函数式技巧仍然非常初级。例如,如果我有一个输入文件,其中每一行都包含几个不同的键值对,需要加载到几个不同的映射中,我不知道如何只处理一次并以函数式结果的形式传递所有映射。也许它就在那里,只是我还没有看到它;但在 Groovy 中,我倾向于做大部分这类事情,我发现自己声明了所有映射,然后使用一个“each”来迭代文件,并在我进行时分配 map1[key1] = value1, map2[key2] = value2 等。

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

无论如何,再次感谢您深思熟虑的评论。

回复 Golman (未验证)

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