艾瑞
艾瑞
新闻资讯
中心动态 学习技巧
Java已经过时了吗?
2024-01-29

本文来自一篇英文文章,作者打算从Java转型Rust的一些思考,值得借鉴。或许也可以成为大家尝试学习或了解Rust的入口。

我是一名有着十年经验的Java开发者。我从2013年开始我的职业生涯,自那时起,我主要使用Java进行开发。我尝试过几种不同的语言(是的,包括C#),但是没有一种语言能够取代Java的地位。

尽管我擅长编写Java应用程序,但我内心深处感到厌倦,我一遍又一遍地做着同样的事情。是的,Java 8 在一定程度上改变了这种情况,新的流API和Lambda很酷,感觉有趣...但只是一段时间而已。

当我开始工作在微服务方面时,情况变得更糟了。对于一个占用4或8GB内存的单体Java servlet应用程序,我可以接受。启动时间也不是一个大问题。它们旨在连续运行几个月甚至几年。但是一个占用2GB内存且启动时间超过2秒的微服务是不可接受的。从领域的角度来看,它真的是一个微服务吗?还有许多其他的问题。而且我不是唯一一个有这些顾虑的人。

尽管我主要从事与业务相关的应用程序开发,但我想编写命令行工具、库和网络应用程序。但是Java成为了我实现真正喜欢的事情的障碍。

Rust(Rust语言)

有许多关于Rust的优点,其中一些并不局限于编写业务应用程序。

极适合命令行工具(CLI)

是的,没有人会使用Java来编写命令行工具,对吧?难道我们想要使用一个在磁盘上占用超过60MB(包括JRE)的命令行工具吗?使用Rust,你可以编写小巧、快速、高效的命令行工具。

更好的资源利用

我们都知道Java是一个吃内存的怪物。与Java 8相比,Java的内存管理已经有了很大的改进。但这还不够。

作为一个概念验证,我们将一个简单应用程序转换成了Rust。在那里,我们并不关心编写性能最佳的代码。我们进行了一个4倍负载的性能测试。结果令人印象深刻。与Java(850MB)相比,我们能够将应用程序运行在8MB以下。这是一个巨大的改进。有趣的是,测试中使用最多内存的并不是我们的Rust应用程序,而是Dynatrace代理。

在CPU方面也观察到了同样的情况。在测试期间,Java应用程序使用了161毫秒的核心,而Rust应用程序只使用了11毫秒的核心。

轻松并发

使用Rust,你可以比使用Java更容易地编写并发应用程序。你有两个选择,消息传递和共享并发(我们喜欢讨厌的)。通常,共享并发很难实现。在Java中,通过查看变量,没有办法知道该对象是否在线程之间共享,而且也没有编译器限制来共享变量。这两个因素使编写并发应用程序变得困难。你可以使用同步块和锁对象(在并发包中),但这些东西都在你想要共享的对象之外,并且用于保护对该对象的访问。

Rust的类型系统使编写并发应用程序变得容易。如果你想共享内存,可以使用Arc;如果你想进行修改,可以使用带有Arc的Mutex。仅仅通过查看变量的类型,你就知道与变量关联的内存是否是共享的。

我可以自信地说,在Rust中编写并发应用程序比在Java中更加容易。这是9个月的经验超过了10年的经验。

轻松的异步编程

异步编程是Rust内置的功能。我们有async(语法糖)和await关键字,使编写异步代码变得容易。

在进行异步编程时,我们只需要关注非常少的细节。Tokio是事实上的标准异步运行时,它提供了许多支持工具。Actix-web是Rust中最稳定、最受欢迎的Web框架。它专为异步编程而设计。

为什么Java仍然存在?

多年来,我一直听到“Java已经过时”的说法。但是Java仍然非常活跃,是最受欢迎的编程语言之一。它广泛用于业务应用程序中。这也有许多很好的原因。

易学易懂

Java非常易于理解,它有一个简单的类型系统。具备基本编程知识的任何人都可以理解大部分复杂的代码。你唯一能编写复杂代码的方法是创建深层次的继承层次结构并在构造函数中进行工作。但这是糟糕的编程方式,不幸的是,它很常见。

“易学易懂”之所以重要,是因为它帮助我们将新开发人员引入项目并快速部署新功能。当能够快速将新功能部署给客户时,就能在竞争中获得优势。

当我编写应用程序时,有三件事我会考虑:

  • 我们能够多快地部署新功能。
  • 我们能够多容易地对现有代码进行更改。
  • 性能

我更关心前两个因素。如果能够快速部署新功能并更轻松地进行更改,就能让客户满意,最终将有益于业务。

另一方面,Rust并不那么简单,因为它与众不同。理解所有权(ownership)、借用检查器(borrow checker)和生命周期(lifetimes)需要时间。Rust的类型系统非常出色。但有时它也会让人感到不知所措。新手将发现理解代码非常具有挑战性。

编译器在开始时可能会令人讨厌。你会遇到各种不同类型的编译器错误。当熟悉之后,你会了解为什么会出现这些错误。但新手可能不喜欢这一点。

生态系统和库

Maven中有超过1100万个可用库。其中大多数库都经过成熟并且易于使用。你可以找到满足所有需求的库。

如果你使用Spring,就知道编写Spring Boot应用程序有多么容易。Spring拥有一个伟大的生态系统,你可以使用spring-web、spring-security、spring-data、spring-cloud、spring-integration等等。还有许多其他与Spring配合使用的库。

Spring Boot使得编写微服务变得容易;只需要添加一些注解,服务就可以运行了。Spring Data就像魔术一样(虽然我不喜欢在我的代码中使用魔术)。你很少需要编写自定义查询,你可以在存储库接口中定义一个方法,Spring Data会根据方法签名生成查询。

这些都是Java库和生态系统的一些例子。

Rust目前只有超过11.8万个库。其中一些库还不够成熟,或者不能直接用于编写业务应用程序。

Actix-web是Rust中最稳定和最受欢迎的Web框架。与同样的Java Spring Boot应用程序相比,Actix-web的性能在另一个水平上。但与Spring Boot相比,需要投入更多的初始工作。Spring Boot提供了自动配置,只需在YML中定义配置,Spring Boot就可以使用它来配置自身。这减少了在设置服务方面需要投入的工作量,并帮助开发人员更多地关注业务逻辑。

rdkafka是Rust中最受欢迎的Kafka客户端。这个库是在Kafka C库之上的一个包装器。在Linux上,只需安装Kafka C库,但在Windows上,情况并非如此;我们需要启用一个功能来编译和链接Kafka C库。同时,rdkafka不会自动将消息转换为Rust结构。我们必须在Kafka消费者中使用serde进行消息传递,还必须编写循环来获取新消息。

由于我更多地从事IDAM工作,必须使用LDAP。Rust ldap3是最稳定的LDAP客户端库。但这也太底层了,不能直接用于业务应用程序。我不得不在ldap3库之上创建一个包装器。对我来说,这是一项有趣的工作,但并非每个人都如此。

我认为这两个原因是保持Java活跃的主要原因。这就是为什么大多数人选择Java来开发业务应用程序。最终,这两个原因归结为一件事。使用Java,我们可以快速发布新功能和进行更改。这正是企业所需要的。

这些真的成问题吗

当你创建一个新的服务时,大多数这些问题都是合理的关注点。因为在这一点上,你花费大部分时间在做纯技术性的事情,比如创建数据库连接、将Kafka消息转换为对象、连接Redis、根据需求实现自定义断路器等等。一旦你处理完这些技术性的事情,你大部分时间都是在处理业务逻辑。在那之后,你将面临的挑战是借用检查器和生命周期,你可以使用一个技巧来避免这两个问题,直到你对这些概念熟悉为止,你可以将所有权传递给方法,然后再从方法中返回。

对于这些技术性的问题,我们可以做一些事情。一种方法是创建低级库的包装器,可以提供高级功能。例如,Spring Boot直接将Kafka中的消息映射为Java对象,我们不需要轮询消息。我们可以为Rust做同样的事情,创建一个高级、易于使用的rdkafka包装器。这样开发人员就可以轻松使用该库,而不必担心底层细节。

同时,我们可以为每个项目中开发人员必须执行的常见任务创建一组库。这对于Rust来说并不常见,我们也为Java做了同样的事情。

尽管我们有这些担忧,但我已经下定决心成为一名全职的Rust开发人员。因为使用Rust很有趣,可以做的事情很多。这可能是我最后一年使用Java进行任何形式的开发。


所以,Java已经过时了吗?不,绝对不是。