Java 随谈 — 聊聊我对 Java 的看法

本文最后更新于 2024年5月19日 16:51

Java 是一种高级的、基于类的面向对象的编程语言,其设计目的是尽可能减少对实现的依赖。它是一种通用编程语言,旨在让程序员一次编写,到处运行(WORA),也就是说,编译后的 Java 代码可以在所有支持 Java 的平台上运行,而无需重新编译。Java 应用程序通常被编译成字节码,可以在任何 Java 虚拟机(JVM)上运行,而不受底层计算机体系结构的限制。Java 的语法与 C 和 C++ 相似,但比它们少了一些底层设施。Java 运行时提供了传统编译语言通常不具备的动态功能(如反射和运行时代码修改)。 - wikipedia

Java 是一门历史悠久的面向对象的编程语言,生态与产品众多,国内与 Java 有关的开发技术栈也是相当热门。我写过不少关于 Java 的博客(在 CSDN),接触它的时间也不短了,去年还学习了两门新兴的编程语言。

今天以一个 Java 用户的身份来聊一聊我个人对 Java 的看法:它的优缺点与其他语言的比较以及我对它的未来的看法

本文默认你是一个有一定 Java 基础的读者,并且对其他编程语言也有一定的了解。

1. Java 的优点

首先呢,Java 它绝对不失为一门好语言。

Java 语言的优点有很多:

  1. 跨平台,Java 语言编写的应用程序可以在不同的操作系统系统上运行(write once, run anywhere)。这种跨平台性是通过 JVM (Java Virtual Machine)。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 Java 虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。
    当然,这种跨平台实现有利有弊,也是我们后面要讨论的重点。
  2. 语法相对比 C/C++ 较容易理解,Java 工具类也特别全面。当我学完 C++ 再来写 Java 代码时直呼太方便了,什么代码库都有现成的供调用。
  3. 生态相当丰富(maven 仓库、安卓开发、服务端开发框架),很多功能只有你想不到,没有它做不到,直接导包使用就可以。
  4. 对线程的支持相当好,线程的创建、销毁、同步等等都有现成的 API 可以使用。同步异步写起来也很方便。
  5. 健壮性,Java 的强类型机制、异常处理、垃圾的自动收集等是 Java 程序健壮性的重要保证。

2. Java 的缺点

但是呢,Java 也有很多为人诟病的问题。

下面就来具体阐述一下我的看法,如果有不周到或者浅显、错误的观点,敬请指出。

2.1 性能与 JVM 的问题

Java 的性能是令人诟病的,其中有相当一部分是因为 Java 的虚拟机 JVM。其性能表现不理想甚至还体现在基于 Java 的 Android 上。何出此言?

众所周知,编程语言大体上可分为两类,一类是编译型,一类是脚本型

Java 表面上虽然是一门编译型语言,但它终归是要在虚拟机里面执行的,光从这一点上来看,它就和脚本语言极为相似(脚本也要依靠解释器去执行)。

即使虚拟机再怎么精简,运行时也是需要占用相当部分容量的内存。这一点也体现在打包一个简单的 Java 项目的时候你会很头疼:即使你只写了一个 hello world 代码,但是你想要把这个 hello world 在系统上以二进制形式直接跑起来,也得打包完整的 JRE。(比如你写好了 Java 代码想 Windows 双击 exe 运行就得打包,因为小白用户总不可能给你提前装个 JRE 吧)

AOT 编译(Ahead-of-time compilation, 预编译)将代码编译成本地机器代码,能够大大提高 Java 程序的性能,但 Java 不能完全依赖 AOT 去提高性能,多数情况 JIT(Just-in-time, 实时编译) 也是必不可少的。因为 Java 语言具有动态性,它的动态性主要体现在反射(reflection)和动态代理(dynamic proxy)上。通过反射,你可以在运行时获取类的信息并动态操作类的属性、方法等。动态代理允许你在运行时创建代理类,拦截对真实对象的调用并执行自定义的逻辑。
这就决定了,你无法在编译时就确定该如何使用 反射 和 动态代理。因此,JVM 无法在编译时优化这些代码,只能在运行时进行优化。这就是 Java 为什么不能完全依赖 AOT 去提高性能的原因。

看到这里,我们似乎就能理解,基于 Java 的 Android 和 Objective-C/Swift 的 iOS,为什么性能会相差甚远(安卓苹果区别较大,编程语言的不同当然只是性能差距的一个重要原因之一,还有原因如:苹果生态对软件有非常一致的规范要求,而且言出法必随 等)。

看到这里有的同学可能就会说了。你一直在吐槽 Java 平台的 JVM,但这是 Java 为跨平台性作出必要的牺牲,有了它,Java 才能实现完美的跨平台。你看看 C 语言或者别的编译型语言有这样的跨平台能力吗?(脚本性语言就不包括在内了,因为脚本性语言本来就是交由解释器来执行的)

你别说,还真有。Go 我觉得就是个比较好的例子。
简单介绍一下这门语言吧:Go(又称 Golang)是由 Google 开发的一门编程语言,注重简洁、高效和并发编程。它具有垃圾回收机制、强大的标准库和并发支持。没有虚拟机,代码直接编译成可执行文件,且支持跨平台编译。

众所周知,越新的语言,它的特性、语法糖和工具链等等功能就越完善。比如说 Java 它相对于 C 和 C++ 就做了很多不错的工具类内置。我当初学完 C 和 C++ 再来学习 Java 的时候就直呼太方便了。

Go 这门语言,它在集成了一些更新更好用的语法糖和工具类的同时。还实现了编程语言一直梦寐以求的功能:跨平台编译。

可别小瞧了这 5 个字,它代表着即使你是 Windows 操作系统,你写好了一份 Go 语言的代码,那么你也可以在 Windows 操作系统上 编译出 LinuxMac OS 系统的二进制文件。(当然系统不止这三个)

Java 和 GO 的编译执行方式对比:

1
2
3
.java -->     .class   -->  jvm 执行(间接和操作系统打交道) 

.go --> 二进制文件.exe --> 操作系统执行

我觉得后者的逻辑是比较符合程序猿直觉的:既然我写一份代码就可以直接跨平台编译执行二进制文件了,为什么还要用那个虚拟机占用内存呢?

2.2 版本问题

GO 语言的开源生态相对 Java 来说还是太弱了,Java 很多时候还依然是必需品。既然如此,有没有办法去改善 Java 的性能问题呢?有,就是尽可能升级 JDK 版本,不要坚守在 Java8。

Java 版本分为非长期支持版本(non-LTS)和长期支持版本(Long Term Support, LTS)。短期支持版本每半年发布一次,长期支持版本每 3 年发布一次。短期支持版本的生命周期只有 6 个月,而长期支持版本的生命周期为 8 年。
目前,Java 21 是最新的 LTS 版本 但刚出还不太稳定,我推荐使用 Java 17,因为它是上个 LTS 版本 使用比较稳定。Springboot3 最低要求也是 JDK17。

性能提升还是相当明显的。
JDK8-17 性能对比
JDK21 性能对比

但是国内很多公司还在使用 JDK 8,甚至还有更低的。直到现在,JDK 8 仍然是国内最流行的版本。我理解如果你的项目已经上线了,那么你肯定不会考虑去升级 JDK 版本,因为要投入不少的时间精力与人力成本,这样做还可能会引发一系列的问题。但是如果你是一个新项目,或者项目有长期规划,那么我觉得你可以考虑一下升级 JDK 版本了。Springboot2 最低要求是 JDK8,如上文提到 Springboot3 最低要求是 JDK17,有不小的跨度。希望开源社区和开源产品可以推动 JDK 的更新吧。

2.3 商业化使用问题

最后就是不得不提的 商业化使用 的问题了。
老话说得好:“你发任你发,我用 Java8”。除了因为上文提到的生态和兼容问题而不升级版本,从商业化角度来看,这么说也并非空穴来风,Java 8u202 是 Oracle 公司当时发布的最后一个免费的 JDK 版本,之后的版本都是收费的。这也是国内很多公司还在使用 JDK 8 的原因之一。

我在写文章的时候刚好看到这篇报道:

Java 自 2019 年起采用付费订阅模式,但 2023 年 1 月再次更改了定价模式,宣布基于公司内总员工数来收取对应的费用,而不是使用 Java SE 的员工数,这种定价模式的改变将对中小型企业产生重大影响,也引发了巨大的争议。甚至有网友直接爆料,「最近 Oracle“要求”公司每年付 72,000,000 英镑去使用 Java,所以公司关闭了所有的 Java 项目,从每台机器上卸载了 Java,并请来了几十个程序员,用 HTML 等重新创建他们的系统。」
源于此,根据 TIOBE 指数显示,从 2023 年 1 月到 2024 年 1 月,Java 失去了 4.34% 的市场份额。从 Java 趋势榜单上也可以非常直观地看到,Java 已经降至自 2001 年 TIOBE 指数榜单推出以来的最低位。
原文链接:https://blog.csdn.net/csdnnews/article/details/135469865

之前就知道 Oracle 在霍霍 JDK 进行商业化,但没想到又搞出这种幺蛾子。
Java 开发国内有多火,相信大家应该都有所耳闻。但好端端天胡开局,搞成这样,不得不令人感叹。
老实讲,我是真不喜欢 Oracle 这家公司。一切都以商业化为目的,包括收购的 Java,MySQL 等。将一门编程语言搞得这么商业化还是独一家(主流的哪个不开源免费)。虽说挣钱嘛不寒碜,但这样真的不体面,吃相是真的不好看。

反观 C#,相较 Java 的收费与严苛的审查规则,C# 自 2014 年以来一直是开源和免费使用的,没有迹象表明要改为订阅模式。今年 C# 也摘得 2023 年编程语言称号。至于为什么 C# 能至于此,可以看看 上文这篇博客,除了这些 也与微软围绕大力推广 .NET 离不开关系

最后,我建议要用 Java 就使用开源免费的 OpenJDK,功能上并没有什么大的差别,有些厂商还有自己定制的 OpenJDK。Linux 上默认的 JDK 就是 OpenJDK。

如果你是 Windows 系统,甚至可以直接安装 Microsoft 提供的 OpenJDK !(选择 .msi 安装包可以帮你安装、设置 JAVA_HOME,一条龙)。

另附上一份 Oracle 旗下的另一款数据库产品 MySQL(大家应该都熟悉)的开源免费替代品 MariaDB 的介绍:

被甲骨文公司收购后,Oracle 大幅调涨 MySQL 商业版的售价,且甲骨文公司不再支持另一个自由软件项目 OpenSolaris 的发展,因此导致自由软件社群们对于 Oracle 是否还会持续支持 MySQL 社群版(MySQL 之中唯一的免费版本)有所隐忧,MySQL 的创始人麦克尔·维德纽斯 以 MySQL 为基础,成立分支计划 MariaDB。 -wikipedia

所以基于开源的考虑,现在 Linux 发行版默认的 JDK 几乎都是 OpenJDK,数据库几乎都是 MariaDB(兼容 MySQL)。(如 Debian 和 ArchLinux)

3. Java 与其他语言的比较

3.1 Java 与 C/C++ 的比较

  • 性能:在性能上 C/C++ 是遥遥领先于 Java 的,这也是很多游戏引擎都用 C/C++ 编写的原因。甚至连 Java 的 JVM 本身都是用 C/C++ 写的。JVM 需要与底层系统进行交互,例如内存管理、线程控制等。而众所周知,C/C++ 是最接近底层的高级语言、是系统级编程语言,性能也优异,具有对这些底层操作的更好支持,使得实现 JVM 时更容易处理这些系统级任务。

  • 语法:Java 语法相对 C/C++ 来说更加简洁,没有指针和复杂的底层操作;C/C++ 语法更加灵活和复杂,支持指针,可以进行更复杂的底层操作。

  • 内存管理:Java 使用垃圾回收机制,程序员无需手动管理内存。这减少了内存泄漏和悬挂指针等问题,但也可能导致一些性能开销;而 C/C++ 没有垃圾回收机制,C/C++ 允许程序员手动管理内存,包括内存的分配和释放。这给了程序员更大的灵活性,但也增加了出错的可能性。

  • 跨平台和编译执行过程:
    Java 被设计为一种 “Write Once, Run Anywhere”(一次编写,到处运行)的语言,即 Java 程序可以在不同平台上运行而无需重新编译。编译执行过程是:代码(.java)先编译成字节码(.class),然后字节码由 JVM 解释执行;
    C/C++ 的可移植性相对较低(针对不同的操作系统和硬件有不同的写法,生成的二进制文件也不通用),它通常需要针对特定平台进行编译。编译执行过程是:直接编译成二进制文件,由操作系统执行。

  • 应用场景:Java 适合开发大型应用程序,例如企业级应用程序、Web 应用程序、移动应用程序等;C/C++ 适合开发系统级应用程序或对性能有较高要求的程序,例如操作系统、驱动程序、游戏引擎、图形应用程序等。

3.2 Java 与 Python 的比较

  • 性能:Python 是脚本语言,性能不如 Java。Python 代码在执行时会被解释器逐行解释,性能较低。而 Java 代码是先编译成字节码(编译优化),然后由 JVM 解释执行。

  • 语法:Python 以其简洁的语法而闻名,比 Java 更简洁。没有类型声明、分号等,代码量更少。

  • 内存管理:都是使用垃圾回收机制,程序员无需手动管理内存。

  • 跨平台和编译执行过程:Python 也是一种跨平台语言,但是 Python 代码在不同平台上运行时需要安装 Python 解释器,通过解释器解释执行代码,而 Java 代码在不同平台上运行时需要安装 JVM。实现思路都是类似的,JVM 在我看来何尝不是种解释器呢。

  • 应用场景:Python 适合用于多种应用场景。例如自动化脚本和任务、Web 应用程序、数据分析、人工智能和自然语言处理等

3.3 Java 与 Go 的比较

  • 性能:Go 语言的性能比 Java 稍好,但是差距不大。Go 被设计为一门轻量级语言,具有很好的性能。它使用了垃圾回收机制,帮助管理内存,避免了一些常见的内存错误。Go 语言的性能优势主要体现在并发编程上,Go 语言的并发编程更加简单高效。

  • 语法:Go 语言的语法比 Java 更简单、直观、清晰,强调代码的可读性和易理解性。

  • 内存管理:都使用垃圾回收机制,程序员无需手动管理内存。

  • 跨平台和编译执行过程:Go 是一种静态编译语言,它的程序可以编译成本地机器码。这意味着 Go 程序不需要依赖于虚拟机,可直接在目标平台上运行,无需安装其他运行时环境。而且 Go 还提供了方便的交叉编译工具,可以生成不同操作系统和体系结构的可执行文件!使在一个平台上编译出另一个平台的可执行文件变得容易。编译执行过程是:代码(.go)直接编译成二进制文件,然后由操作系统执行。

  • 应用场景:Go 适合用于开发 网络编程、分布式系统、云原生开发、Web 应用程序、系统工具、命令行工具等。

3.4 Java 与 C# 的比较

  • 性能:在性能方面,Java 和 C# 在很多方面都非常接近,并且难以明确地说哪一个性能更好。二者都是类似的编译执行过程,也都使用垃圾回收机制。PS:主要是,我几乎没怎么用过 C#,所以不好评价。

  • 语法:Java 语法是强类型、面向对象的编程范式,语法相对传统和熟悉;C# 的语法设计更加灵活和现代化。它引入了一些先进的语言特性,如 LINQ(Language Integrated Query)、异步编程等,使得代码更为简洁。C#使用属性(Attributes),而Java使用注解(Annotations)来添加元数据和特殊行为。

  • 内存管理:都是使用垃圾回收机制,程序员无需手动管理内存。

  • 跨平台和编译执行过程:C# 虽然最初是为 Windows 平台设计的,但通过 .NET Core 和 .NET 5+ 的推动,现在也支持跨平台开发。C# 程序可以使用跨平台的 .NET Core 运行时来执行。

  • 应用场景:Java 广泛应用于企业级应用、大型系统、Web 开发、移动应用(Android 开发)、云计算等领域。由于其平台无关性和强大的生态系统,Java 在企业级开发中有着重要地位。C# 主要用于 Windows 平台上的开发,包括桌面应用、Web 应用、游戏开发(Unity 游戏引擎)、云服务等。近年来,通过 .NET Core 和 .NET 5+ 的跨平台支持,C# 在开发跨平台应用上的应用场景也在不断增加。

4. 对 Java 的未来的展望

4.1 GraalVM 的广泛使用,提高性能

GraalVM 是由 Oracle 开发的一个高性能、通用的虚拟机,支持多种编程语言,包括 Java、JavaScript、Python、Ruby 等。以下是一些关键特性和用途:
多语言支持:GraalVM 支持多种编程语言,使得开发者可以在同一个运行时环境中使用不同语言编写的代码,包括 Java、JavaScript、Python、Ruby 等。这为混合语言的开发提供了便利。
即时编译器(JIT):GraalVM 包含一个先进的 JIT 编译器,可以提供比传统的 Java 虚拟机更好的性能。它允许将程序源代码直接编译成机器码,而不需要预先将代码编译成字节码。
Native Image:GraalVM 提供了 Native Image 工具,可以将 Java 程序直接编译成本地可执行文件,减少启动时间和内存占用。也就是我们提到的 AOT 编译。
嵌入式执行:GraalVM 可以嵌入到其他应用程序中,使得开发者可以在自己的应用中利用 GraalVM 的多语言支持和性能优势。
支持 Java 17+ 版本。

4.2 使用 Kotlin 代替 Java

Kotlin 是一种静态类型的编程语言,它可以编译成 Java 字节码,也可以编译成本地机器码。Kotlin 由 JetBrains 开发,目前已经成为 Android 开发的首选语言。Kotlin 与 Java 兼容,可以与 Java 代码无缝集成,也可以直接使用 Kotlin 编写 Android 应用程序。Kotlin 语法简洁,易于学习,具有很好的可读性和可维护性。Kotlin 也可以嵌入到其他应用程序中,使得开发者可以在自己的应用中利用 Kotlin 的多语言支持和性能优势。Kotlin 也是一种跨平台语言,Kotlin/Native 允许将 Kotlin 代码编译成本地机器代码,而不是 Java 字节码,可以脱离 JVM,直接在支持的平台上运行编译后的二进制文件。

但是如果还是虚拟机运行,好像有点换汤不换药?:)


Java 随谈 — 聊聊我对 Java 的看法
https://blog.ovvv.top/posts/f7c262de/
作者
mobeicanyue
发布于
2024年1月10日 02:02
更新于
2024年5月19日 16:51
许可协议