本文最初发布于 Peter Wayner 博客,经原作者授权由 InfoQ 中文站翻译并分享。
在计算历史上,1995 年是一段疯狂的岁月。首先 Java 出现了,随后 JavaScript 也出现了。Java 和 JavaScript 的名字看起来像是一对双胞胎,但实际上它们差别巨大,Java 是被编写和静态定型的,而 JavaScript 则是被解释和动态定型的。但这仅仅是这两个完全不同的语言的技术差别的一个开始,Node.js 的出现使得两种语言经历了两条完全不同的发展轨迹。
如果你比较早的接触了 IT 技术,那么你或许记得 Java 曾经风靡一时,每个人都将其视为一项革命,认为它将完全替代计算。但事实证明,这一预测只有一部分是正确的,Java 统治了安卓手机、企业计算和一些嵌入式设备,如蓝光光碟。但它从来没有统治过桌面或浏览器。人们曾尝试出售过小应用程序和 Java 工具的强大,但是表现平平。
同时,之前被程序员们错认为是 Java“双胞胎”的 JavaScript,如今也能独当一面了。在 HTML 和 web 推出 Borg 的几年间,JavaScript 一直紧随其后,AJAX 的出现使得 JavaScript 突然之间拥有了力量,打破了之前的局面。
随后 Node.js 诞生了,大大提高了开发速度。JavaScript 不仅在服务器上比大多数人预期的要快,甚至与 Java 或者其它工具相比,速度也要快。JavaScript 能够更加稳定地处理小的、快速的和无休止的数据请求,因此,当网页变得更加动态时,Node.js 就变得更加常用了。
虽然这在 20 年前可能是无法想象的,但是现在 Java 和 JavaScript 正在争夺编程领域的“统治权”,它们一个强调以坚固的工程和架构为深层基础,另一个强调简洁和普遍性。到底是老式的编译器驱动的 Java 会立于不败之地,还是在 Node.js 帮助下的 JavaScript 将所向披靡呢?
Java 获胜之处:坚如磐石的基础看到这个小标题,可能有些开发者会有质疑。当然,我们不否认 Java 还存在一些小 Bug,但是相对而言,Java 已经算是很“坚固”的了,Node.js 想要让我拥有这样的信心,还需要许多年。
事实上,要写出与 Sun/Oracle 在测试 Java 虚拟机时所写数量相同的回归测试,JavaScript 开发者或许要花上几十年。当你启动 JVM 时,你将获得来自一个质量可靠的管理者的 20 年经验,而这个管理者一直决心要统治企业服务器领域。
不过,JavaScript 也在迅速迎头赶上。当 Web 的大部分依赖于 JavaScript 执行引擎时,开发者的时间大部分花在了打磨边边角角上面。然而,所有的创新都有一个缺点,那就是新的功能可能扩散太快,以至于开发者们来不及吸收这些功能。一些老派的开发者经常会对充斥着最新 ECMAScript 句法的增强特性感到困惑。另外,这些新代码可能还会导致某些旧版浏览器崩溃。
创新性的预处理器,如 CoffeeScript 和 JSX 等,源源不断地出现,对于需要这些功能的开发者来说是件好事,但是对于不需要的开发者来说增加了难度。
尽管 Java 也在不断推出新的功能和选项,但总体而言,它是一个稳定的平台,它给那些需要开发更长久的东西的开发者带来了便利。
Node.js 获胜之处:普遍性多亏了 Node.js,JavaScript 在服务器以及浏览器领域找到了一席之地。你给服务器写的代码很可能在浏览器上也能运行。很明显,比起在 Java 和 JavaScript 中分别写代码,直接使用 JavaScript 更简单。
如果你决定要把 Java 中的服务器业务逻辑迁移到浏览器中,或者老板执意要你把给浏览器写的逻辑迁移到服务器上。在这两种情况下,Node.js 和 JavaScript 都能让代码迁移变得更简单。
不仅如此,Node.js 的领导地位似乎还在扩大,例如比较复杂的 Web 框架,类似 React,是要把代码运行在服务器还是客户端上呢?另外,还有可能出现这种情况,代码前一天是运行在客户端上的,但是后一天可能就运行在服务器上。某些智能的逻辑将在运行时根据负载、闲置 RAM 容量和其它因素来决定究竟代码运行在什么上面。有些框架会把 JavaScript 作为一条查询,输入到数据库,并在那里执行。你的代码可能在任何地方运行,所以,你很难了解究竟是在什么地方,因为代码根本不会返回任何东西。但是也无需担心,因为你不需要考虑太多细节。
Java 获胜之处:更好的集成开发环境 (IDE)Java 开发者拥有三大 IDE,Eclipse、NetBeans 和 IntelliJ,这三个 IDE 是与调试程序、反编译器和服务器良好地集成的顶尖工具。每个工具都经过了数年的开发,拥有忠实的用户、坚固的生态系统和数不尽的插件。
大多数 Node.js 开发者会将文字输入命令行,再编码到他们最喜爱的文本编辑器中。诚然,市面上最好的一些文本编辑器,像 Atom,都拥有琳琅满目且几乎无所不能的插件,但如果和 Eclipse 进行比较,Node.js 给人的感觉要更老式一些。在不久的将来,Atari 操纵杆将代替我们的鼠标。
另外,有些 Node.js 开发者会使用 Eclipse 或 Visual Studio。开发者对 Node.js 突然激增的兴趣可能会有新工具诞生,例如IBM 的 Node-RED 给我们提供了一些极具吸引力的方法,但是这些工具还远未达到像 Eclipse 或 IntelliJ 那样的完整度和统治地位。
但奇怪的是,开发者好像并没有使用这些工具。命令行本该在 35 年前 Mac 到来时就消失,但却没人把这个消息告诉 Node.js 的开发者们。但是选择一直都在那里。例如,WebStorm 就是一个可靠的由 JetBrains 开发的商业化工具,它集成了许多命令行构建工具。
当然,如果你正在寻找一款能够编辑和调整代码的集成开发环境,那么现在支持 Node.js 的新工具已经足够使用了。但如果你希望集成开发环境能够让你一边操作正在运行的源代码,一边编辑代码,那么 Java 的工具显然会更强大一些。
Node.js 获胜之处:数据库查询一些较新的数据库,如 CouchDB 和 MongoDB 的查询是由 JavaScript 编写的。将 Node.js 和数据库调用合并不需要任何换挡,也不需要记住任何句法差异。
而许多 Java 开发者都在使用 SQL。即使是在他们使用 Java DB——前身是 Derby (一种由 Java 编写的数据库)时,他们的查询也是用 SQL 写的。你可能会以为他们会简单地调用 Java 方法,但其实没有,开发者必须要用 SQL 写数据库代码,然后再用 Derby 解析 SQL。 虽然 SQL 是很好的语言,但是它与 Java 完全不同,许多开发团队需要有不同的人来分别写 SQL 和 Java。
更糟糕的是,许多 Java 程序员使用复杂的库和模式来将 SQL 查询数据转换成 Java 对象,目的是让自己能够将这些东西重新导入到模板中。这个过程非常疯狂,而且非常浪费。
Java 获胜之处:类型许多入门级的编程课程都使用 Java,因为许多程序员都喜欢静态类型编码,静态类型编码很简洁而且安全。在编译器找出了一些明显的 bug 后,代码看起来更加严谨了。
不过,JavaScript 也在追赶,一些开发者已经转到 TypeScript。TypeScript 是一个静态类型的 JavaScript 超集,首先会应用所有的类型检查手段,然后剔除掉运行在浏览器上的 JavaScript 堆栈中的一些东西。
对于喜欢类型的开发者来说,TypeScript 足以让你喜欢上 JavaScript。当然,你可以把 JavaScript 这种模仿视为是对 Java 最真诚的恭维,并且继续使用 Java,因为 Java 从一开始就是使用静态类型的。
Node.js 获胜之处:语法灵活性JavaScript 曾经是一个简单的语言,用于弹出警示框和双重检查输入表。后来,开发者社区创造了 JavaScript 的许多不同版本,它们能够被转编译为浏览器可用的东西。例如,CoffeeScript 提供了一些不同的句法,旨在使标点符号更加清晰。React/Vue 群体将 HTML 和 JavaScript 混合。此外,还有针对类型爱好者的 TypeScript 和针对功能语言信徒的 LiveScript。
而在 Java 中,你会发现有很多创新,但这些创新由于某些原因,并未用预处理器进行表达。还有一些语言如 Kotlin、Scala 和 Clojure,为了 JVM 专门变成了字节代码,但不知为何,它们可以说是完全独立的语言。对于喜欢尝试不同的代码编写方式或标点符号的 JavaScript 程序员来说,所有的预处理器均使他们的生活变得更加有趣了。
Java 获胜之处:简单的构建流程
复杂的构建工具如 Ant 和 Maven 使 Java 编程发生了革命。但还是有一个问题,开发者需要将说明用 XML 写出来,而 XML 并不是一个支持编程逻辑的数据格式。
当然,使用嵌套标签来表达分支相对而言比较简单,但是仅仅是为了构建,就要从 Java 切换到 XML,有些令人讨厌。有了 JavaScript 后,你就不需要再切换。
之前,Node.js 的构建很简单,只需要编辑代码,点击“运行”就可以了。但是随着 Node.js 开发者不断改进流程,添加了一些预处理器来抓取你最喜欢的 JavaScript 方言,并将这种方言转换成可以运行的东西。然后,Node 包管理器需要找到正确的库,因为有时可能会找不到,所以需要花时间寻找某个工件正确的版本号,而这个工件必须在单独的步骤中自行构建。而且,如果你在工件库中引入了一些错误,那么,这个版本号便无效了,需要重新做。
Java 也有与 Node.js 方法类似的复杂的构建过程,但给人的感觉不会比 Node.js 更复杂,从某种意义上说,Maven 和 Ant 貌似已经成为了 Java 基础的一部分,许多粗糙的边角已经被去除了,因此构建的工作成功率更高了。
如果非要对它们的构建难度进行衡量的话,它们可能不分伯仲,但如果从 JavaScript 快速增加的复杂度的角度来看,Java 在这方面获胜了。
Node.js 获胜之处:JSON当数据库给出答案时,Java 需要花费大量时间把结果变成 Java 对象。开发者会就 POJO 映射、Hibernate 和其它工具争辩上好几个小时。配置这些东西耗费数小时甚至数天时间。最终,在所有的转换之后,Java 代码获得了 Java 对象。而来到配置阶段时,Java 使用的仍然是 XML,并且提供了 2 个主要的解析器,这给开发者带来了更多的烦恼。
如今,许多 Web 服务和数据库都以JSON的形式返回数据,JSON 是 JavaScript 天然的一部分。JSON 现在非常常见和有用,以至于许多 Java 开发者都在使用这种格式,而且还有一些非常好的 JSON 解析器可以作为 Java 库被使用。相比之下,JSON 本身就是 JavaScript 基础的一部分,不需要库,直接使用就可以了。
Java 获胜之处:远程调试Java 拥有许多非常棒的监控机器集群的工具。JVM 有深层的钩子和精细的剖析工具来帮助我们识别瓶颈和故障。Java 企业堆栈上运行着全世界最复杂的服务器,而使用这些服务器的公司对遥测的要求非常之高,所有这些监控和调试工具都较为成熟,并且可以立即部署它们。
Node.js 获胜之处:桌面也许有人在使用 Java 小程序,但我仍然保留了一些可以点击运行的 Java JAR 文件。总体来说,桌面领域大体上是不用 Java 的。另一方面,随着浏览器取代了桌面的大部分角色,JavaScript 的作用也越来越大。当微软重写了 Office 并使其能够在浏览器上运行时,一切就注定了。如果你还想了解更多,那么市面上还有许多有趣的选择,比如Electron,它能够抓取你的 Web 代码,然后转换成独立的桌面 app。
Java 获胜之处:手持设备安卓 app 大多都是用 Java 写的,而且 90% 的新手机都运行着各种版本的安卓系统。很多人根本就不使用桌面了,因为手机已经可以做任何事情了。
许多开发者都在编写 Node.js Web 应用,这些应用主要用在 iPhone 和安卓手机上的移动浏览器上。如果这些应用写得比较好,性能通常会比较好。但 Java 正以另外的一种方式入侵。最新的 Chromebook 将支持安卓应用,从而给 Java 开发者进入 Chromebook 用户的桌面开辟了道路。那么 Java 是否仍有机会征服桌面呢?
Node.js 获胜之处:库Java 提供了大量的库,而且这些库做得都非常好,文本索引工具如 Lucene 和计算机视觉工具包如 OpenCV 都是非常好的开源项目,它们都将成为其它重大项目的基石。JavaScript 程序员也在追赶,创造出了很多了不起的项目。
在某些领域,Java 就是一个远程的存储器,市场上可能有无数不同的 Web 框架,所以 Java 不能在这个新兴市场中参与竞争。
Java 获胜之处:坚固的工程虽然这点很难量化,但是因为 Java 的数据基础非常强大,许多重大的科学工作中使用的许多复杂的程序包均是用 Java 写的。Sun 公司花了大量的时间来获取工具类的详情。市场上有 BigIntegers、精巧的 IO 例程和复杂的日期代码,它们均实现了格里高里和罗马儒略日历。
JavaScript 适合简单的任务,但是其内部有很多令人混淆的地方。举一个简单的例子,JavaScript 针对没有答案的函数会生成三种不同的答案,分别是:undefined、NaN 和 null。那么,哪一个是正确的呢?其实每个答案都有各自的作用,其中一个便是驱使程序员保持代码统一。JavaScript 更怪异的方面是虽然它在简单的表格工作很少出问题,但对于复杂的数学和定型工作而言,JavaScript 并不是一个好选择。
Node.js 获胜之处:速度Node.js 的速度一直很受开发者的欢迎,数据输入和答案输出的速度如同闪电。Node.js 不需要单独设置线程,也没有上锁等令人头疼的问题,也没有拖慢速度的额外开销,只需要写一些简单的代码,Node.js 就会快速地采取正确的步骤。
Node.js 的回调模型已经改变了其编程方式,使程序员避免同时操作多个任务。JavaScript 引擎能够确定何时运行什么代码。因此,程序员可以编写更短和事件驱动的代码,并且关注重要的逻辑。
但是 Node.js 也存在一些问题,Node.js 代码要尽可能的简单一点且工作正常,因为如果它锁死了,整个服务器都可能锁死。操作系统开发者努力创建了许多安全网来抵抗编程错误,但 Node.js 会让这些安全网失效。
此外,当程序员将回调函数如俄罗斯套娃一层又一层不断地嵌套时,还会出现一个代码复杂性的问题。一个回调还好,但一系列的回调令人抓狂,好消息是 Promise 模型很容易读。但你需要记住,在执行代码行期间,许多事情都可能发生。
Java 获胜之处:线程代码速度快虽然好,但更重要的是代码要准确,而使用 Java 可以享受到一些额外功能:
Java 的 Web 服务器是多线程的。创建多个线程可能要花费时间和存储,但这是值得的。因为,如果一个线程锁死了,其它的还可以继续用。如果一个线程需要很久的计算时间,那么其它线程可以分担。更重要的是,代码一直在掌管之下,并且能够进行调整。
如果某一个 Node.js 请求运行速度过慢,其它请求的速度也会降下来。Node.js 只有 1 个线程,因此只有它准备好了,事件才能被处理。或许它看起来超级快,但是本质上它的架构就如同春节的时候,邮局只开一个办理窗口一样,即它不能同时处理多个请求。
人们花了几十年构建智能的操作系统,能够同时处理许多不同进程的操作系统。那为什么还要回到那个电脑只能处理单线程的年代呢?的确,处理多个线程意味着要做更多的工作,但是多线程更强大,不是吗?
Node.js 获胜之处:势头看见硅谷的开发者总是积极献身于最新和最具颠覆性的东西,但有时清理掉遗毒也很重要。Java 有新的 IO 例程,但是它也有一些旧的代码,例如许多小程序和 util 类会阻挡你前进的道路。Node.js 在 Git 库中也留下了很多垃圾,但是由于 Node.js 出现的比 Java 晚几十年,且 Node.js 开发者还在研发许多针对 Web 堆栈软件的增强功能,所以,Node.js 动力十足。
两方不分伯仲之处:Java 和 Node.js 之间的交叉编译
服务器到底是用 Java 还是 Node.js 的辩论可能还会持续很多年,但与其它辩论不同的是,这场辩论可能会是双赢的局面。Java 可以交叉编译到 JavaScript 中去,谷歌就经常在 Google Web Toolkit 中这么做,而且谷歌最受欢迎的网站也运行着 Java 代码,这些代码就是从 Java 翻译为 JavaScript 的。
当然,反过来也是如此。JavaScript 引擎如Rhino和 Nashorn同样在 Java 应用里面运行 JavaScript,然后你可以链接到这些应用。如果还不满足的话,你还可以链接到谷歌的V8 引擎。
所有的 Java 和 JavaScript 代码都可以和谐地彼此链接,因此,你不需要在两者之间选择。
作者简介:Peter Wayner 是 InfoWorld 的特约编辑,并且是 16 本涉及不同主题的书的作者,包括《开源软件(统统免费)》,《自动化汽车(未来出行)》,《隐私增强计算(透明数据库)》,《数字交易(数字现金)》,《和隐写术(密码学的消失)》。他的书定期发布在 InfoWorld 上,并且他还为许多大小型软件项目提供咨询。他关于机器人汽车的《未来出行》这本书的第二版已经出版。查看英文原文:Node.js vs. Java: An epic battle for developer mindshare
推荐阅读开发人员应该了解的五款 Julia IDE
推荐阅读点击了解更多