我为什么使用 Java

可能有比 Java 更好的语言,这取决于工作要求。但我还没有看到任何能让我放弃它的东西。
208 位读者喜欢这篇文章。
Coffee beans

Pixabay。CC0。

我相信我从 1997 年开始使用 Java,那时距离 Java 1.1 问世 不久。从那时起,总的来说,我非常喜欢用 Java 编程;虽然我承认现在,我可能更常写 Groovy 脚本,而不是用 Java 编写“严肃的代码”。

我来自 FORTRANPL/1Pascal 和最后的 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 用户,而且我还没有看到任何可能让我放弃它的东西。

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,这让我对 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 及更高版本中的函数式接口对代码维护者和开发人员来说都是巨大的好处,仅仅是通过减少由“此处”对象产生的样板代码,这些对象的唯一目的是为单个函数提供实现。显而易见的事实是,这减少了打字,这有点顺便;真正的好处是代码更紧凑、更易读,并且当不被大量“如何”包围时,“什么”更清晰可见。

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

我的 Java(和 Groovy)函数式技能仍然非常初级。例如,如果我有一个输入文件,其中每行包含要加载到多个不同映射中的几个不同的键值对,我不知道有什么方法可以只处理一次并交付所有映射作为函数结果。也许它在那里,只是我还没有看到它;但在 Groovy 中,我倾向于完成大部分此类工作,我发现自己声明了所有映射,然后使用“each”来迭代文件,并在进行过程中分配 map1[key1] = value1、map2[key2] = value2 等。

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

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

回复 作者:Golman (未验证)

知识共享许可协议本作品根据知识共享署名-相同方式共享 4.0 国际许可协议获得许可。
© . All rights reserved.