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 语言的优点有很多:
- 跨平台,Java 语言编写的应用程序可以在不同的操作系统系统上运行(write once, run anywhere)。这种跨平台性是通过 JVM (Java Virtual Machine)。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 Java 虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。
当然,这种跨平台实现有利有弊
,也是我们后面要讨论的重点。 - 语法相对比 C/C++ 较容易理解,Java 工具类也特别全面。当我学完 C++ 再来写 Java 代码时直呼太方便了,什么代码库都有现成的供调用。
- 生态相当丰富(maven 仓库、安卓开发、服务端开发框架),很多功能只有你想不到,没有它做不到,直接导包使用就可以。
- 对线程的支持相当好,线程的创建、销毁、同步等等都有现成的 API 可以使用。同步异步写起来也很方便。
- 健壮性,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
操作系统上 编译出 Linux
和 Mac OS
系统的二进制文件。(当然系统不止这三个)
Java 和 GO 的编译执行方式对比:
1 |
|
我觉得后者的逻辑是比较符合程序猿直觉
的:既然我写一份代码就可以直接跨平台编译执行二进制文件了,为什么还要用那个虚拟机占用内存呢?
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,直接在支持的平台上运行编译后的二进制文件。
但是如果还是虚拟机运行,好像有点换汤不换药?:)