我为什么使用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上,然后使用相同的MTS编译器在IBM OS/VS1上,让我的生活变得轻松了很多。 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体验的方法。 对我来说,这些中的大多数目前还不是很有趣; 同样,这更多地反映了我的典型工作流程,(远) less那些语言带来的功能的函数。 但是,这些进化步骤之一已成为我编程武器库中不可或缺的一部分: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)函数式 Fu 仍然非常初级。 例如,如果我有一个输入文件,其中每行包含几个不同的键值对,这些键值对要加载到几个不同的映射中,我不知道有什么方法可以只处理一次并交付所有映射作为函数结果。 也许有,只是我还没有见过; 但在 Groovy 中,我倾向于做这类事情,我发现自己声明了所有的映射,然后使用“each”来迭代文件,并在进行时分配 map1[key1] = value1, map2[key2] = value2 等。

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

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

回复 ,作者:Golman (未验证)

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