Java 25 已发布 – 有哪些新特性?

图0:Java 25 已发布 - 有哪些新特性?Oracle 已宣布推出 Java 25,这是其卓越的编程语言和开发平台的最新版本。在正式发布数月前,通过今年初以来举办的数次 Java 大会陆续披露的信息,我们或多或少已经了解到新版本将带来什么。例如,在今年的 SpringI/O 大会上,Nicolai Parlog 谈到了即将到来的 JEP512,该特性将使初学者更易于学习 Java。正如他所演示的,我们将能够从为初学者设计的繁琐但笨重的 “Hello World” 示例:

public class HelloWorld {
    public static void main(String[] args) {
       System.out.println("Hello, World!");
    }
}

转变为 JEP 被 Java 25 版本采纳后更为简洁的对应版本:

void main() {
    IO.println("Hello, World!");
}

无需再等待,因为从昨天起这已成为现实!

元素周期表

随后在 Oracle 的官方 Java 活动 JavaOne 上,Brian Goetz 的演讲“Java 语言的未来走向?”揭示了很多信息,并为语言设定了未来的发展方向,特别侧重于 Amber 和 Valhalla 项目。这不仅关乎版本 25,更关乎更广阔的展望和未来的期望,值得一看。

但这些只是两个例子。总而言之,JDK 25 带来了十六项增强,范围从 Java 语言本身的核心到库,再到安全性、性能、运行时和监控。其中一些关键的 JEP 包括:

Oracle JDK 25 语言特性

JEP 507:模式、instanceof 和 switch 中的基本类型(第 3 次预览)
通过允许在所有模式上下文中使用基本类型来增强模式匹配,并扩展 instanceof 和 switch 以支持所有基本类型。
开发者因此可以通过消除在使用模式匹配、instanceof 和 switch 时遇到的有关基本类型的限制来增强模式匹配。它还允许在所有模式上下文中使用基本类型模式,并扩展 instanceof 和 switch 以支持所有基本类型。

JEP 512:紧凑源文件和实例 main 方法
这就是前述“Hello World”示例相关的 JEP。
其目的是让学生能够以简洁的方式编写他们的第一个程序,而无需理解为大型程序设计的语言特性,以便他们的代码能够随着技能的提升而优雅地增长。

JEP 513:灵活的构造函数体
在构造函数体中,允许在显式构造函数调用(即 super(…) 或 this(…))之前出现语句。此类语句不能引用正在构建的对象,但可以初始化其字段并执行其他安全计算。此更改允许许多构造函数更自然地表达。它还允许字段在类中的其他代码(例如从超类构造函数调用的方法)可见之前进行初始化,从而通过在显式调用构造函数之前进行输入验证和安全计算来提高安全性和可靠性。

Oracle JDK 25 库

JEP 505:结构化并发(第 5 次预览)
结构化并发将运行在不同线程中的相关任务组视为一个工作单元,通过简化并发编程,帮助开发者提高多线程代码的可维护性、可靠性和可观察性。

JEP 508:Vector API(第 10 个孵化器)
引入一个 API 来表达向量计算,这些计算在运行时可靠地编译为受支持 CPU 架构上的最优向量指令。因此,开发者可以实现优于等效标量计算的性能,这常用于 AI 推理和计算场景。

安全性/性能/监控

JEP 510:密钥派生函数 API
通过为密钥派生函数(一种从密钥和其他数据派生附加密钥的加密算法)提供 API,让开发者为新兴的量子计算环境做好准备。

JEP 514:提前命令行工效学
通过更轻松地创建提前(AOT)缓存且不损失表达性来加速开发效率。这通过简化常见用例所需的命令来加速 Java 应用程序的启动。

JEP 509:JFR CPU 时间分析(实验性)
通过增强 JDK Flight Recorder (JFR) 以在 Linux 上捕获更准确的 CPU 时间分析信息,帮助识别需要优化的程序元素,从而提高 Java 程序的生产力和效率。

新版本中包含的所有 JEP 的简要总结:

  • JEP 470 加密对象的 PEM 编码(预览)
  • JEP 502 稳定值(预览)
  • JEP 505 结构化并发(第五次预览)
  • JEP 506 作用域值
  • JEP 507 模式、instanceof 和 switch 中的基本类型(第三次预览)
  • JEP 508 Vector API(第十个孵化器)
  • JEP 509 JFR CPU 时间分析(实验性)
  • JEP 510 密钥派生函数 API
  • JEP 511 模块导入声明
  • JEP 512 紧凑源文件和实例 main 方法
  • JEP 513 灵活的构造函数体
  • JEP 514 提前命令行工效学
  • JEP 515 提前方法分析
  • JEP 518 JFR 协作采样
  • JEP 519 紧凑对象头
  • JEP 520 JFR 方法计时与跟踪

与往常一样,该版本还包括数百项较小的增强和数千个错误修复。

至此,正如 Oracle Java 平台高级副总裁兼 OpenJDK 管理委员会主席 Georges Saab 所说:

Java 今年迎来了 30 周年纪念,这是一个重要的里程碑,该平台和语言持续演进,以帮助开发者快速轻松地构建融合创新 AI 和安全功能的应用程序。

但在结束之前,非常重要的一点是,Oracle 计划为 Java 25 提供至少八年的长期支持,这使组织能够灵活地以最少的维护将应用程序在生产环境中保留更长时间,并最终按照自己的条件进行迁移。
根据 Oracle 免费条款和条件 (NFTC),Oracle JDK 25 计划在 2028 年 9 月之前接收季度安全和性能更新,此后发布的 JDK 25 更新将根据 Java SE OTN 许可证 (OTN) 提供,该许可证计划持续到至少 2033 年 9 月。

最后,在 2023 年底的“I Programmer Java 2023 回顾”中,我回答了一个紧迫的问题:“既然有 C#、Go、Rust 和 Python,为什么还要选择 Java?”。这是因为 Java 一直是企业的最爱:

企业过去和现在都在谈论 Java。只需看看财富 500 强公司对它的依赖程度就知道了。是的,蓝筹公司喜爱它。原因有很多。企业最看重的是向后兼容性,它们 notoriously 对激进的更新和升级过敏。20 年前编写的、基于 Java 5 的系统应该能够在版本 8 下编译和运行。稳定性才是关键。

这在 2025 年仍然成立吗?
是的,确实如此。Java 继续影响着企业,在云中扮演着最重要的角色,并且目前正在征服 DevOps 和 AI 领域。

当然,将所有的功劳都归于语言本身有点不公平。成功的另一个神奇因素当然是可敬的 JVM,它看起来正在成为所有语言的熔炉。这背后有一个重要的原因。
在我最近与 Flavio Glock 关于他的 PerlOnJava 项目(一个设计运行在 JVM 上的 Perl 编程语言实现)的访谈中,我问道:与 JVM 等现代后端集成是否是 Perl 保持活力并持续繁荣的先决条件?

Flavio 给出的答案很有启发性:

在这个云驱动的时代,与 JVM 等现代后端集成对于 Perl 持续保持相关性至关重要。PerlOnJava 等项目展示了 Perl 在新环境中适应和发展壮大的能力。通过利用 JVM,Perl 可以访问广泛的库生态系统,利用现代性能优化,并更轻松地集成到企业级解决方案中,例如云服务和容器化环境。

所以 Java 生态系统的影响远远超出了语言本身……

共有 230 条评论

  1. 更多新程序应该用Java/基于JVM来编写。

    Java失去流行度的大部分原因已不复存在,如今它已成为一个极其稳定成熟的生态系统。

    我能打开十年前写的Clojure程序,它运行得_非常棒_;而半年前写的TypeScript程序却需要大量更新和清理。

    • 甲骨文让我如坐针毡。能否在不招致甲骨文怒火的情况下使用Java?或许只要确保使用OpenJDK/跳过某些障碍就能安然无恙。或者干脆改用其他语言,彻底摆脱这种隐忧。若想获得类似Java的体验又避免甲骨文“断腿”风险,C#正是理想选择。

      我实在不知如何在不违反甲骨文EULA的前提下使用Java。要么花时间研究安全使用方法,要么干脆弃用Java。对绿地项目而言,Java并非必需品。现有众多优质替代方案,我更倾向于选择后者。

      • 直接用OpenJDK(唯一缺点是半年要升级一次)或第三方发行版(多数人用Eclipse,红帽客户就用红帽版)。其实没传言中那么复杂。

        若使用甲骨文官方JDK发行版,说明你是企业客户,理应具备应对其许可条款的资源。

        • “我使用的语言运行时发行版(或其版本)是否正确,以免陷入法律纠纷?”——这是Java的竞争对手们无需考虑的问题。

          即便使用OpenJDK,也如同悬在头顶的达摩克利斯之剑。若忘记更新OpenJDK,Oracle随时可能找上门。而选择放弃Java,我便无需承担这种风险。风险或许不大,但它确实存在——而Java的竞争对手根本不存在这种风险。

          编程语言领域的竞争如此激烈,优质选择如此丰富,Java根本承受不起这类摩擦点的存在。

          编辑:我混淆了Oracle OpenJDK和Oracle JDK的概念。它们是不同的产品。Oracle OpenJDK的许可证并未变更,而Oracle JDK的许可证已变更。这是其他语言无需担心的问题/风险,但混淆两者的责任在我。

          • > 若忘记更新OpenJDK,Oracle可能追究我的责任

            我肯定漏看了GPLv2的这部分条款。

            Oracle确实以特殊非开源免费许可证分发另一套(非OpenJDK)Java发行版,其中包含条款规定用户不得使用下个LTS版本之后的更新。这反而更添混乱:除非需要Oracle付费支持或其特定产品要求,否则根本无需使用Oracle的特殊发行版。

          • >即使用OpenJDK也如同悬在头顶的达摩克利斯之剑。

            不,真的不是。说实话,人们似乎费尽心思胡说八道来贬低Java。讨厌一种语言的理由有很多,这完全没问题。但既然你可以选择…不用它,就没有必要对它胡说八道。

            • 我以为OpenJDK每次发布新版本都会更改许可证。所以楼上才说“OpenJDK唯一的缺点是半年就要升级一次”对吧?

              • 不,他们这么说是因为OpenJDK团队构建的代码库版本仅支持6个月,直到下个版本发布。

                其他厂商构建的OpenJDK代码库版本支持周期则各不相同。

              • 我认为没人能撤销你已拥有的GPL许可软件。

                • 查阅《美国法典》第17编第203条和第304条。我认为35年后(至少在美国)是有可能撤销许可的。

          • 这话出自一位对甲骨文持怀疑态度的人之口。以上说法均不属实。使用OpenJDK时已不存在实际阻碍。根据父评论所述,您无需每六个月升级一次,多数人仅使用LTS版本即可。

          • “我使用的语言运行时发行版(或其版本)是否正确,以免陷入法律纠纷?”——这是Java竞争对手们根本无需考虑的问题。

            我不确定这是否完全正确。我认为,如果你下载特定版本的Anaconda(用于Python),可能会遇到需要付费的情况。

            例如在Anaconda.com网站,用户可下载其发行版(即官方构建版本),但细则注明:“员工/承包商超过200人的组织使用Anaconda产品需购买商业许可证,除非该组织符合折扣或免费使用资格。”

            我认为PSF许可证属于宽松型许可,允许使用Python二进制版本而无需开发者公开源代码。

            因此下载Anaconda作为Python发行版(构建版本),相当于下载Oracle JDK(Oracle基于OpenJDK的商业构建版本)。

          • 这是否因为据我所知,Java的竞争对手本就没有提供商业支持服务?

            这和Linux的情况类似。红帽企业版Linux并非免费,但若有人因许可协议复杂而不敢使用Linux,那才奇怪。

          • “我使用的语言运行时发行版(或其版本)是否合法?”——这是Java竞争对手根本无需考虑的问题。

            呃…抱歉,这纯属无稽之谈。市面上存在大量需付费的商业Python发行版,例如ActiveState ActivePython、Anaconda Enterprise等。

            若在商业环境中未经授权下载并使用其预编译的ActivePython安装程序,即构成违约行为,将面临法律风险。

            > 这是其他语言完全不必担心的问题/风险,

            不,在提供商业支持的众多语言中(Python/C++/Perl/NodeJS等),您绝对必须警惕此类风险。

            > 即使使用OpenJDK也是悬在头顶的达摩克利斯之剑。

            纯属赤裸裸的谎言。

          • > 若忘记更新OpenJDK,Oracle可能找我麻烦。

            什么?

            • OpenJDK的许可协议绝非小事。看看Oracle不得不列出的庞大表格和冗长条款才能说明许可内容。https://www.oracle.com/java/technologies/javase/jdk-faqs.htm…(在常见问题页面展开首级下拉菜单即可查看“许可矩阵”)

              这简直一团乱麻,难道在我深陷Java生态圈时,许可证还要再次变更吗?

              编辑:OpenJDK似乎始终采用GPLv2许可证,不明白为何表格里会有这么多不同条目。我可能把OpenJDK和Oracle JDK混淆了。之前回复那位说OpenJDK需要半年更新一次的人,恐怕也搞混了。要准确区分各种JDK版本实在太难,很容易混淆或产生困惑。再次强调,其他Java竞争者都不存在这种问题。

              • OpenJDK的许可协议非常简单(GPLv2+Classpath),就像gcc/g++及其运行时库例外条款一样。

                Oracle JDK的许可则更为复杂。虽然你可以免费使用它,但在下一个长期支持版本(LTS)之后,你必须迁移到LTS版本或付费获取更新。除非需要Oracle的技术支持,或应用程序明确要求使用Oracle JDK,否则没有理由选择Oracle JDK。其源代码与OpenJDK完全相同。

                https://blogs.oracle.com/java/post/free-java-license

                • 如今使用Oracle JDK究竟有何优势?多年前曾见JetBrains某些IDE建议使用它而非OpenJDK,但此后再未见过类似情况。

                  • Oracle JDK提供长期支持(LTS),包含定期安全补丁和关键漏洞修复,即使是旧版LTS发布也持续维护(据我所知超过十年,但需核实)。

                    OpenJDK社区版本通常仅提供至下个发布版本的更新(约6个月)。

                    Oracle提供付费商业支持合同:包含保障性补丁时间表、全天候企业级支持、性能问题排查及合规性保障。

                    您还可在Oracle JDK基础上开发功能并获得支持。例如SAPJVM就实现了热调试功能。

              • > OpenJDK的许可问题不容小觑。

                ?? 操作非常简单。请访问OpenJDK官网并阅读以下内容:

                https://openjdk.org/legal/gplv2+ce.html

          • 究竟哪些是JVM的竞争对手(注意:这里指的是JVM,而非Java本身)?若您感兴趣,随时可以使用Kotlin或Scala。这两种语言都能与拥有20多年历史的Java生态系统实现绝佳的互操作性。

            编辑补充:唯一具备竞争力的生态系统是JS/TS(因其数十亿预装用户)和C#。

            > 即使使用OpenJDK也是悬在头顶的达摩克利斯之剑。若忘记更新OpenJDK,Oracle随时可能找上门。选择不使用Java就能规避这种风险——虽然风险可能不大,但Java竞争对手根本不存在这种隐患。

            这纯属荒谬的夸大其词。

        • > 唯一缺点是每半年必须升级

          Eclipse等LTS版OpenJDK发行版(如17、21等)支持周期更长[1]。甚至JDK 11和8至今仍在获取更新。

          确实需要为安全修复等更新运行时环境,但其他语言同样如此。

          [1] https://adoptium.net/support

        • 当存在零摩擦的替代方案时,这些操作都显得多余。人生苦短,何必自找麻烦。

          • 你能解释一下所谓的摩擦是什么吗?如果在商业环境中下载并安装ActiveState的Python发行版,未经阅读就接受许可协议,日后遭到法律诉讼,你会说Python存在过多摩擦吗?

            只需访问https://openjdk.org/并点击“下载”。或者在 macOS 上执行 brew install openjdk / 在 Linux 上执行 apt install openjdk

            零摩擦。

          • 根本不存在摩擦。不想付费就别用商业产品,事情就是这么简单。

          • 安装Oracle JDK通常需要_主动选择同意_,因为…你知道的,他们有必须接受的许可协议。

            所以根本不存在阻力,除非有_非常特殊的需求_,否则大家都用开源版本。

      • > Oracle让我太不安了。能否在不用担心招致Oracle怒火的情况下使用Java?

        嘿!我在微软工作,曾参与发布微软构建的OpenJDK版本。

        我可以明确告诉你:是的,你可以毫无顾虑地使用Java。只要不使用带有特定许可限制的供应商提供的商业二进制文件即可。

        我们构建的OpenJDK可免费用于任何场景,且在Azure工作负载上提供商业支持(就是那种能提交工单让我们排查问题的服务),无需额外付费。

      • > 若想获得类似Java的体验又不想担心甲骨文断我腿,C#就是最佳选择。

        微软在这方面真的比甲骨文强吗?

        • 若比较.NET与Java,微软确实更胜一筹。微软可能对部分开发工具(如Visual Studio等)收费,但.NET平台本身始终完全免费。

          • 我认为“始终免费”的表述并不准确

            但更重要的是,它不仅是免费的,更是ECMA标准的集合体https://learn.microsoft.com/en-us/dotnet/fundamentals/standa

            请别误会:我严重怀疑目前仅存在一个真正的标准实现(业余项目和弃用项目不在此列),但个人认为“实际标准”结合“真实参考实现”远胜于单纯的参考实现

            趁编辑窗口还未关闭,补充说明:兄弟评论提及的MAUI采用MIT许可证https://github.com/dotnet/maui

            https://github.com/dotnet/blazor (Apache 2) 已标记为存档状态,并指向https://github.com/dotnet/aspnetcore (MIT) 许可协议,但其读我文件中搜索blazor毫无结果 :shrug:

            • > 我认为“一直是”这个说法并不准确

              若要严格讲究,他们指的是“.NET”而非“.NET Framework”或“.NET Core”,所以本质上指的是随.NET 5及更高版本推出的内容。

              • 将这三者割裂开来的想法本身就是典型的微软作风,让讨论变得极其痛苦

          • 而.NET真正实现跨平台已长达11年(自.NET Core 3.0发布以来)。此后再无许可/专利/诉讼问题。

            优秀的跨平台GUI工具包(MAUI),出色的WASM引擎(Blazor)。

            即将发布的.NET 10必将震撼全场。

            • 官方MAUI不还是基本“除Linux外全支持”吗?我这两年没关注,只记得网上某个角落有个非官方的GTK实现,但Linux上始终没有官方支持。

              • Linux桌面市场份额微乎其微,没必要为此投入大量资源。况且支持Linux版MAUI等于助长桌面领域的竞争对手,而维持该领域主导地位对微软至关重要。我认为这也是他们未将优秀的WPF移植到Linux的原因。

                更何况Linux桌面生态混乱不堪。我从未深入研究过Wayland/X11/KDE/Gnome等组件的具体功能与定位。只知道某些发行版会频繁更换桌面环境,时而宣称某套方案最佳,时而又贬低另一套方案,这种风向转变简直令人应接不暇。所幸Canonical团队让Ubuntu桌面基本能满足我的使用需求,尽管相比Windows仍存在诸多不足。

                我认为当你需要覆盖Windows、Linux、macOS甚至移动平台的跨平台支持,且进行严肃项目开发时,就会选择Qt。

        • 要看情况。若你经历过史蒂夫·鲍尔默时代,就会明白微软几乎会在每项开发技术上背叛你。

          不过C#和.NET确实有着相当可靠的记录。

      • 你无需费尽周折。若不想与甲骨文打交道,就别当甲骨文的企业客户,直接获取开源JDK发行版即可。

        • > 直接获取OpenJDK发行版

          来源包括:

          – 甲骨文官方 jdk.java.net
          – 微软 microsoft.com/openjdk
          – 红帽 …
          – Azul Systems …
          – 亚马逊
          – Bell Soft
          – Canonical(Ubuntu预装其构建的OpenJDK二进制文件)
          – 自行编译?

          • 直接访问https://openjdk.org/点击“下载”链接即可。

            或通过操作系统包管理器安装openjdk。问题解决。

            就像安装其他软件一样,懂吧?

            • 该下载链接指向jdk.java.net,该站点托管甲骨文构建的OpenJDK版本。

      • 我的半阴谋论观点是:Rust的成功部分源于科技巨头们在寻找Java的“法律安全”替代方案。

        谷歌与甲骨文长达数年的诉讼案令亚马逊和脸书等公司如坐针毡。与此同时,一种安全高效且无附加条件的编程语言在开源的Apache许可证下悄然兴起。相关企业迅速围绕该语言成立了基金会,采用501(c)(6)条款的行业协会模式,而非“公益性质”的非营利组织。这意味着_只要成为会员并缴纳会费就不会被起诉_——这正是所有企业的诉求。如今它们持续提供资金,并雇佣部分编译器开发者,确保该项目未来20年甚至更长时间的稳定运行。

        该语言本身确实能完美满足其需求,这显然是企业支持它的主要原因,但法律层面的保障无疑加速了其普及进程。

        • 不确定你时间线中的具体节点,但若你尚未知晓:亚马逊拥有名为Corretto的自有Java发行版,其首个公开版本发布于2018年:

          https://downloads.corretto.aws/#/overview

        • 这种阴谋论不仅能解释Rust的成功,也能解释Go语言、C#/.NET以及任何其他Java竞争者的崛起。

          我认为90%的原因在于Oracle及其律师主导的商业模式,10%则源于语言本身丑陋的特性——现有库文件极其难看且难以阅读,充斥着各种工厂模式和抽象工厂模式,所有设计模式都被像宗教般强制灌输,完全不顾具体场景是否适用。

    • Java在大型后端系统中极其流行且应用广泛。我猜这里很多人没接触过这类系统?看到楼主这类评论时我总是很惊讶,因为在我职业生涯中,Java几乎无处不在。

      • 过去八年间,多家大型工程组织正逐步放弃后端Java,转向Go语言。这些转型往往受到谷歌等企业的示范效应或Kubernetes等项目的“激励”,更被“易学、易构建、易部署”的语言承诺所吸引。

        • > 被“简单学习、构建和部署”的承诺所吸引

          这描述相当准确,而我作为每日使用Java的开发者对此深有体会。就部署而言,Go确实更胜一筹。我宁愿部署Go编写的服务而非Spring Boot服务。但话说回来,我更喜欢用Java构建单体应用——那些塞满业务逻辑的大型代码库。就这方面而言,我个人认为Go并不擅长。

          • 为什么会这样?Go是否在某些方面存在明显缺陷?

            • 企业常需处理旧数据库、消息队列、SOAP服务及遗留系统。Java拥有海量成熟的连接器(甚至比Python更多!)、支持完善的JDBC驱动程序以及厂商支持的SDK。

              此外,Java在事务管理、依赖注入、验证框架、AOP式横切关注点等特性方面表现更佳。

              Java的集合流具备高度可定制性(过滤/映射/归约等),远胜于在Go中编写第10000个for循环。无需额外代码即可实现自动并行流处理。

              Go的性能分析工具(尤其是内存分析)相当原始,恕难取悦。JVM分析工具的性能优势可达数量级。其他工具同样如此——垃圾回收调优、监控等。Java的Flight Recorder和VisualVM堪称绝妙。

              话虽如此,Go在内存高效、紧凑的网络软件领域仍具优势,例如精简的k8s控制器。不过坦白说,Rust正在侵蚀这个领域。

            • 我虽非他们,但论运维洞察力,鲜有工具能超越JVM。它拥有海量可调参数,具备极其丰富的动态代码加载机制(反射、类加载器、新模块系统,以及曾经强大的沙箱系统——可惜已被移除),而这两者的交汇点正是 JMX:通过 API 实现动态可调的部署。这如同拥有 JVM 本地的功能开关,无需重启即可随时调整。

              当然,这并非人人都喜欢的口味,而且肯定会有不少人跳出来用“是啊,但是…”来为Go语言或其他非JVM平台辩护。我可不是在贬低你的喜好!只是对我而言,JVM就是最棒的选择

          • 你在部署Java/Spring Boot应用时遇到过什么挑战?我这边一直顺风顺水。

        • 谷歌内部的Go语言创建者们刻意忽略了这样一个事实:在谷歌内部,Java代码的数量远超Go代码。

        • Go正逐渐演变为Java 1.5+——看看泛型的加入就知道了。

          顺便说一句,如果你愿意,可以对Java进行AOT编译…虽然生成的二进制文件可能比Go的更大,但无所谓啦…

          [Meta] …天啊,我这儿都快变成pjlmp了,哈哈

        • > 由多家大型工程组织推动转型

          这类趋势的问题在于往往是炒作,你永远不知道实际进展或长期演变。

          我见过组织发布声明后,仅转换5%业务就放弃转型另辟蹊径,但只有初始声明能登上新闻头条。

          > 被“易学易建易部署”的语言承诺所吸引

          若从头推倒重来,一切都显得简单。闪亮的新玩具总是极具吸引力。

      • 我想我们讨论的是面向用户的桌面软件。

      • 大多数大型云平台都是基于Java构建的…

      • 我认为容器技术的兴起以及原生编译运行能力的出现,已经消除了支持JVM的论点。如今借助Docker镜像,完全掌控开发和部署环境变得轻而易举,在我看来这是更优的解决方案。简而言之——容器技术将从根本上取代Java。

        • > 简而言之——容器技术将从根本上取代Java

          为何不能共存?

          > 消除了支持JVM的论点

          这种批评过于拘泥技术定义。我怀疑现在的新Java或JVM用户真的还在纠结这个。更多是关于生态系统、成熟度等问题。

    • Java持续普及面临的最大风险,毫无疑问是其文化生态——老派Java程序员和旧式Java程序仍在无谓地冗长,尽管该语言如今已具备(几乎)与其他流行现代语言同样简洁的工具。

      这是一场艰难的逆流之战,但它或许能攀上山巅,只因它仍是如此庞然巨物。

      • 当.stream()出现时一切就注定失败。何必强迫人们用.stream()实现函数式编程?更何况流甚至不可复用,我几乎希望他们直接发明个基于奇异UTF-8字符的新运算符,而非增加那9个冗余字符。字体里本该为.stream()设计连字符的。

        现在再来聊聊.collect(toList())…

        还有那些丑陋得像豆子的记录类型…

        Java向来以冗长著称。但或许每行多加9个字符就能解决问题。

        • 没人抱怨Rust的turbo-fish运算符,它同样相当冗长。况且Java早已引入了直接的toList()/toArray()方法。

              let v = (1..5).collect::<Vec<i32>>(); // 酷炫的Rust
          
        • 从JDK 16起,Stream已提供.toList()方法,可省去.collect()的十个字符。

        • 语言设计师很难取悦所有美学主义者。

    • 我暗自期待 Kotlin 和 Compose 能让 JVM 上的桌面应用重焕生机 :-)。

      • 我对 Kotlin 持反对态度,因为它似乎只能在 JetBrains 的 IDE 中使用。我完全失明,而根据我的经验,JetBrains 工具在可访问性和易用性方面远不及安装了所有 Java 扩展的 VS Code。在我任职过的所有公司,没人介意我不使用Idea。但考虑到目前似乎没有优秀的VS Code Kotlin工具链,若必须在工作中使用Kotlin,那将是一场痛苦的折磨。

      • 我用JavaFX开发桌面应用(一个Kotlin项目,一个纯Java项目)。看不出有什么理由需要等待,它完全具备生产环境部署能力。

        • 我的意思是,我也觉得它真的很棒!只是希望它能流行起来,而不是那些ElectronJS…玩意儿。

    • > 我能打开十年前写的Clojure程序,它依然运行良好

      这是得益于JVM还是Clojure本身的特性?因为我的Clojurescript项目也有类似经历。随便拿个旧nbb脚本都能直接运行——偶尔需要更新npm依赖,但绝大多数情况下根本不会出现严重故障。与此同时,我刚花了半天时间折腾奇怪的Python依赖和虚拟环境魔法舞步,只为运行五个相互依赖的脚本。

      • 作者是否将Clojure程序打包成jar文件尚不明确。若是如此,那确实要归功于JVM。

        无论如何,Clojure的主流构建方式已发生变化。十年前可能使用lein,如今新项目多采用deps.edn。

      • 我认为这源于Clojure对向后兼容性的理念,而非JVM本身。若我理解有误,请指正!

        • 我认为深层原因远不止于此。Clojure的诸多设计细节都令人拍案叫绝。使用十年后我依然乐在其中——其他任何语言(我尝试过不少)都未能让我保持如此持久的愉悦感。

    • Java存在大多数命令式语言的通病,即缺乏工具严格执行的可变状态与不可变状态的清晰分离。许多大型Java程序试图通过使用不可变集合来规避此问题,这确实有所改善但效果有限。

      Java还因其面向对象特性而面临额外问题,在高负载下会导致混乱的父子关系。

      • Valhalla 应该能通过不可变值类在一定程度上解决这个问题。

    • 我对Java最大的不满在于其缺乏统一性。存在多种可选的JDK实现方案,多种构建系统等。C#生态圈虽小,但体系更为精简。

      • 不同JDK版本几乎都基于OpenJDK构建。Maven和Gradle已覆盖绝大多数使用场景,复杂度并不算高。

        • 我认为复杂度相当高,尤其对生态系统的新手而言。流行的JDK管理工具sdkman提供17种可安装的JDK版本:

          https://sdkman.io/jdks/

          对比之下,DotNet SDK仅需选择单一提供商,且编译器命令行内置了顶级包管理功能,几乎所有项目都不必再为“gradle”或“maven”这类构建工具费心选择。

          • 页面顶部提到的默认设置其实并未解决这个问题…

            • 这根本没解决问题,尤其当sdkman只是可选的额外工具时。若与他人协作,该默认设置也未必是团队实际开发的版本。若你只是想选个JDK却连sdkman的存在都不知道,明智的人会质疑为何生态系统分裂成17个JDK版本;或者你根本不会察觉,直接从甲骨文官网下载。我见过太多新手(甚至老手!)Java开发者因此陷入混乱。

              至今我仍需反复确认新开发者是否为项目安装了正确JDK版本。

              Sdkman文档同样无法解决Java世界中多构建系统的难题——这在.NET等生态中根本不存在。

    • 我认为Java是大多数中大型项目,或涉及线程操作及复杂/优化IO场景的最佳选择。

      尤其在硬件架构再度碎片化的当下,希望它能重拾相关性。

      Spring框架正在拖累Java的声誉。我知道Spring Boot稍好些,但它本身就是个怪物。

      但令人遗憾的是,Python似乎已赢得这场战争。尽管它相当糟糕,却足以胜任大多数场景。

      如今我看到有人尝试用Rust开发生产级AI系统。

      • 拥有超过20年的Java开发经验,我更倾向于使用Python进行开发,原因有很多,但最主要的是涉及Java的项目总是伴随着同样愚蠢的政治斗争和组织冲突。我注意到Python项目往往更令人愉悦且摩擦更少,这可能源于相关组织本身更开放包容,或许也因为它们更年轻。我不确定。在我接触过的每家财富500强企业里,所有Java项目最终都沦为同样的混乱地狱,我必须逃离这种环境。

      • > 我认为Java是大多数中大型项目的最佳语言

        结合上下文来看…

        > 我认为Spring框架拖累了Java的声誉。我知道Spring Boot更好,但它简直是个怪物。

        当真如此?Spring虽非完美,但在中大型环境中绝对优于许多其他框架。那些缺乏文档或库已弃用的项目,其维护难度带来的灾难性后果远超Spring。

    • 在我所接触的圈子里,Java不受欢迎是因为它冗长乏味。

      坦白说,如今我认为这些已不是主要问题。

      我更倾向Clojure程序,但现阶段宁可选Java也不要TypeScript。

      • > 它冗长乏味

        遵循传统Python范式的代码被称为“Pythonic”。

        遵循Java范式的代码则被称为“糟糕透顶”。

        坦白说,我从未专业编写过Java代码,仅在十年前为几个小型业余项目写过,加上学生时代的一些实践,因此我的观点不值你阅读它的像素成本——但我看到大多数Java代码时都感到极度恐惧。

        无止境的抽象层级。明明能写个简单函数,偏要搞个“ThingDoer”类,里面只有个叫“doThing”的单一方法。运行时内省和反射无处不在。堆栈跟踪记录里全是“.invoke”和“.run”这类函数调用的无尽栈。

        我一直以为这些都是Java严格类型系统的副产品,但请有人纠正我。为什么Java的编程范式看起来如此糟糕?

        • 坦白说,许多人将“Pythonic”视为糟糕的委婉说法。职业生涯中我见过多个庞大的Python代码库在陷入混乱后被重写为Java,其中最令人尴尬的案例或许是谷歌内部代码审查工具Mondrian——它正是由Guido van Rossum亲手编写的。

          Java代码库显得更抽象的原因之一在于,它们试图解决脚本世界往往回避或采用难以扩展方式处理的问题。而由于Java采用名义类型系统,解决这些问题需要命名。

          例如,Java代码库中的大量抽象设计旨在实现深度可测试性。这正是依赖注入的核心驱动力,而BeanFactory等框架的诞生也源于此。那么Python如何解决这个问题?通常它们几乎不具备Java开发者标准下的测试体系!这正是Python在机器学习研究领域盛行的原因——该领域代码库往往是小型可抛弃实验,也解释了为何Django在短暂流行后,便逐渐淡出更广泛的服务器/大数据应用场景。

          另一复杂性来源在于可插拔生态系统的构建。数据库经JDBC抽象后,再通过ORM进行二次抽象,随后可能被Micronaut或Spring进一步抽象。每个层级都存在多种实现标准API的竞争方案——这种现象在脚本语言领域则罕见得多。其弊端在于脚本代码库对所选库的依赖性更强。将Java代码库从一种数据库或ORM迁移至另一种要容易得多,因为核心API均已标准化。

        • 这是文化差异而非语言问题。以下是PlantUML中一个缺乏冗余抽象层级的JSON解析器实现:

          https://github.com/plantuml/plantuml/blob/master/src/main/ja

          • 我认为文化才是语言的唯一定义者。

            是否存在像你分享的json解析器那样,拥有完整企业级生态系统的开源库?类似的Stack Overflow解答?大型语言模型输出?教程?YouTube视频?

            我认为答案是否定的。

            这和C#面临的问题如出一辙。仅仅添加替代范式毫无意义。真正重要的是生态系统中绝大多数代码的结构方式。在Java中,主流就是企业级代码。多数代码属于粘合代码,因此你不得不遵循主流模式——除非愿意编写无穷无尽的封装器…

            另一方面,尽管TypeScript支持大量类似C#的企业级冗余特性,但生态系统的主流实践却是基于简单函数、回调和选项对象的编程方式。这并非企业级风格。我无需使用装饰器就能调用zod。

            那些厌恶企业级代码、偏好简洁编程的人,除非整个文化发生转变,否则无法转向Java或C#——无论这两种语言堆砌多少花哨特性都无济于事。

            • >> 另一方面,尽管TypeScript支持大量类似C#的企业级冗余特性,但其生态系统的主流实践仍以简单函数、回调和选项对象为核心,而非企业级风格。

              回归文化层面,TypeScript社区由哪些人构成?虽然C#开发者被吸引而来,但更多成员来自JavaScript背景。这种差异深刻影响了文化发展方向。

              退一步说,C#开发者常常需要从事前端工作。他们可以选择业界主流的React,也可以另辟蹊径。多数人选择React,其中有些人或许仍会抱怨必须为这项工作切换思维模式。前端领域显然更分散,但规模限制了C#开发者像在后端那样影响模式的能力。

              我认为Java开发者在前端领域面临类似处境。以Blazor为例,C#模式在决策中的权重其实很小。事实上,鉴于React是行业标准,许多C#拥趸也会默认选择它。

            • 我基本认同你的观点,唯独“完全定义”这点例外。文化固然是强大力量,但个人拥有选择自由,而语言本身也支持这些选择。

            • 一针见血。语言与使用者密不可分,数百万小时投入生态系统的成果无法重来。

            • > C#面临同样问题。仅添加替代范式毫无意义。

              C#仍更胜一筹,因其拥有诸多实用的开发体验改进:从对象初始化器到无处不在的IEnumerable。它降低了抽象层的高度,并优化了操作抽象层的体验。

              不过我仅接触过基于.NET Core的C#微服务开发

        • 这些并非Java本身的范式——它们只是平庸企业开发者的惯用做法,而Java作为主流平台,此类开发者比比皆是。

          至于语言本身,后期版本已通过钻石运算符、lambda表达式、局部变量类型推断等特性大幅精简冗余。

          无论如何,代码被阅读的次数远多于编写次数,因此若稍许冗余能提升代码可读性,我完全接受。

        • ThingDoer.doThing这类写法,往往只是将函数式编程硬塞进面向对象的枷锁。十多年前Java 8引入了一级函数和lambda表达式,大大减少了将简单行为封装为完整类的必要性。

        • 这种Java风格的成因之一在于该语言长期缺乏强大特性。例如lambda表达式直至Java 8(2014年)才出现,此前开发者需绕过此限制进行开发。常见的变通方案是:在方法上方添加注解,并辅以反射机制。例如标注@PrePersist的生命周期回调方法,本质上等同于注册一个_函数_。整个Lombok库就是为规避Java不便之处而构建的庞大黑客方案(我认为如今已不再必要)。

        • 我认为很大程度上是使用者和特定文化氛围使然。许多企业级Java程序员似乎坚信:堆砌抽象层级、追求冗长代码、编写微小却无实际作用的方法,就能获得更优解决方案。其实用Java编写简洁实用的代码完全可行。不过空值处理始终是个棘手问题——传统方法只会增加行数和分支逻辑。较新的Optional类处理空值虽冗长,但属于横向扩展。

          • 在我看来,空值处理是Java至今唯一真正糟糕的技术缺陷

            • 我多年未在实战中见过空指针异常。我们构建流程使用NullAway——效果极佳。

        • > 源于Java严格类型系统的副产品

          1. Java 8之前缺乏一等函数,导致旧API充斥着继承和反射,即便是最简单的任务也必须继承类并重写方法。

          Java 11之后代码变得更简洁且更具函数式风格,但旧库依然存在。

          这些库提供的过度可扩展性在某些场景确实有用,但这类场景寥寥无几。

          2. 注解处理器出现得太晚——导致大量需要检查对象结构(如序列化)的库都依赖大量反射实现。

          我将举例说明专为“现代”Java设计的框架是什么样子的。

          Micronaut提供名为Micronaut数据JDBC的功能——你只需声明带少量注解的方法,例如List<Book> queryTop10BooksByYear(int year),它就会自动生成JDBC + SQL代码,并处理将其注入服务的工作。返回对象可以是纯POJO,完全避免了ORM框架附带的代理对象机制。目前我尚未在Python中见到如此简洁的实现。所有这些操作都在编译时通过注解处理器完成。

        • 我认为编程不必如此,但Java代码沿袭这种模式已久,惯性思维根深蒂固。当让Java程序员参与Ruby或Python代码库协作时,这种现象尤为明显——稍不留神,他们就会将你的代码库瞬间改造成企业级混乱的层层间接结构。

        • 作为见过几乎所有编程语言糟糕代码的人,我认为这更多源于惯性思维和抗拒改变的惰性。当语言和平台以惊人速度进步时,那些深植于生态系统的糟糕模式仍难以根除。

        • 正如其他人所言,这是文化问题而非语言本身。90年代末至00年代初编写的C++甚至某些Python代码都存在同样的模式滥用症。这源于对《四人帮模式》书籍的盲目追随,以及对面向对象编程的过度迷恋。此外,这些语言本身在非面向对象的抽象能力和代码复用机制上存在缺陷——例如Java迟至多年后才引入lambda表达式,导致开发者不得不依赖带有“invoke”方法的一次性辅助类。

          正如其他评论所言,这是文化使然。所幸Java社区正推动函数式编程与抽象数据类型(ADT)建模,并将其命名为“数据导向编程”。

          呃,我认为Java类型系统既不严格,也不是这种伪技术崇拜乱象的根源。问题可能在于许多企业程序员将设计模式视为万能构建块,而非隐性涌现的结构。

    • 这更可能与人们用单线程工作者替换多线程服务有关。

    • 最近用IntelliJ尝试Java开发,看着IDE的代码补全功能见证Java的演变历程颇有意思。

      Java里大量代码都长这样:

          void foo(Bar bar);
      

      其中 Bar 是接口,多数情况下它仅包含单一方法,因此看起来像必须封装在类中的回调函数。幸运的是,Java 允许创建匿名类来调用这些方法。

          void foo(new Bar { @override boolean baz(Fish fish) { return false; } });
      

      我推测由于这种模式极为常见,Java后来引入了类似下面的“lambda表达式”(我从IDE提示中得知):

          foo((Fish fish) -> false);
      

      但若某个类包含Bar.baz方法签名,却将其命名为fries()呢?其实可以这样处理(来自IntelliJ的另一条提示):

          foo(this::fries);
      

      这看似是声明回调的复杂方式,但其含义是:若你确实实现了同名方法,只需传递实例;否则可使用语法糖,例如:

         saveMenuItem.registerMenuClickListener(myMenuClickHandler);
         saveButton.registerClickListener(myMenuClickHandler::onMenuClick);
      

      不过Java里确实存在许多令人费解的设计。随手列举几个:

      1. 不存在无符号整数。“byte”的取值范围为-127至128。我认为这意味着创建32位RGBA结构并非易事,因为你只能选择使用带符号的“red”字段,或者采用16位整数来存储8位值。顺便提一下,我通过简单测试(使用arr1[]索引arr2[]取值,再解析生成arr3[])测得Java运行速度仅为C语言的一半,但对于基础的低级二维图形处理而言,这速度应该足够快。

      2. String.split 方法要求正则表达式参数,且没有标准的非正则表达式分割方式。这曾让我非常困惑,但幸运的是编写自定义的 .split 方法非常简单,因此问题不大。

      3. 可通过this()调用不同构造函数,但必须作为构造函数中的首个语句。这点相当离谱!若要求构造函数调用前不可访问成员变量尚可理解,但强制首语句规则意味着:当需根据另一个构造函数的参数计算当前构造函数参数时,必须在括号内完成运算。

      到目前为止,我只希望Java能实现两点。首先是能在接口中实现方法,这样当你拥有接口时就能使用这些方法,而非依赖静态方法。其次希望@NotNull能成为默认设置。Kotlin已解决了这个问题,因此若你欣赏TypeScript的类型安全特性,学习Kotlin会是个不错的选择。

    • 在使用它二十多年后,我认为它的时代早已过去,它不再是构建企业应用程序最高效的方式。你很幸运那个Clojure程序还能在新版本JVM上运行,因为我经手的许多大型应用程序根本无法迁移到新版Java。事实上,这种情况在我身上反复出现过多次。我几乎从未接触过使用最新JVM版本的项目,任职过的公司始终停留在“Java 8”这类过时版本上。这种状况令人恼火,但绝非个例。

      • 几年前我们用Java 8开发了应用,并随每个LTS版本更新,目前用的是21版。除了Javax包更名为Jakarta这类小问题,至今都相当顺利。

  2. Java始终是如此坚实可靠的技术基石…且历久弥坚!它或许不是最时髦的语言,但始终稳定可靠。我们用Java 1.4开发的应用至今仍在Java 21 LTS上运行良好,并计划近期升级至最新LTS版本(Java 25)。Java永不落伍!

    • 若没有JetBrains卓越的工具链和精妙的学徒计划,Java今日的成就恐怕难以企及。

      • 自1990年代末起,Java便拥有强大的集成开发环境,其中部分工具甚至完全免费!

      • 在JetBrains出现之前,Java世界早已存在大量面向学生的程序。甚至还有一款专注于学生的集成开发环境BlueJ,它通过丰富的可视化呈现帮助编程新手快速上手——这款工具自1999年便已问世。

        • 遗憾的是,BlueJ几乎完全错误地教导了面向对象编程的原理。

      • Java在Eclipse基金会和IDE的黄金时代就已蓬勃发展。JetBrains其实是近年才兴起的。

        • > JetBrains其实是近年才兴起的。

          JetBrains已有25年历史,几乎与Java同龄。

          • 直到10-15年前,IntelliJ才开始广泛使用。而在此之前Java早已蓬勃发展。

            • 2005年伦敦投资银行已大量采用它。次年Resharper也已普及。

          • 大约十年前,我所在的圈子里Eclipse仍是主流编辑器。

            • 在我圈子里至今仍是,不过在家我始终是Netbeans的拥趸。

              从Borland的MS-DOS产品时代起我就钟情IDE,但始终对IntelliJ提不起兴趣,Android Studio更让我反感加深。

          • 当年我也用Eclipse,但维基确实记载IDEA 1.0(2001年1月)早于Eclipse IDE(2001年11月)。

            NetBeans于1999年被Sun收购,2000年6月开源。

    • 题外话,至今记得2009年那款用Java开发的Gmail应用,当时在我的Symbian触屏手机上运行。界面可爱得要命,功能却相当实用。

    • 不错,我以前写过几个Swing应用,一直想着重启它们,但又不想做太多修改——毕竟它们大多是玩具性质的,虽然对我很有用。我打算试试看!

      • Swing现在还行吗?通常人们说Java现在不错时,我总觉得他们没把Swing算进去。

        • Swing就是Swing,它始终如一地优秀(见仁见智)。据我所知,它并未彻底过时,开发者已更新渲染机制以更好地利用现代硬件,但它绝非现代工具包。不过仍在维护中,依然可用。

          JavaFX很不错(我特别喜欢FX),且持续维护,还具备跨平台性。我记得他们刚发布了25版。但它与Swing是完全不同的设计范式。

          • 确实,但二十年前的Java子集同样如此;这与人们所说的“如今Java很优秀”并非同一回事。

        • 我曾在二十多年前编写过一个Swing应用,用于手术室登记器官移植。此后Swing拯救了无数生命。它早已足够优秀。

        • 作为参考,JetBrains平台正是基于Swing构建的。我认为这正是他们能同时支持Linux、macOS和Windows平台的关键因素——不同于Eclipse SWT为每个目标平台都提供原生代码的做法。

          • 据我所知,JetBrains为优化其Swing组件的视觉效果付出了巨大努力,他们能做到这一点是因为作为资源雄厚、以工程为核心的公司,其主力产品正是用户全天使用且常自掏腰包购买的图形界面应用。Swing在此类场景下可能被低估(若需跨平台部署)确实是个有趣的假设,但这与它是否适合边缘化GUI应用是两回事。

        • 它依然优秀如昔。我欣赏其稳定性与出色的交互模型,但若需要现代化的嵌入式地图或图表,还是选择网页界面吧。若执意使用Swing,务必尝试flatlaf库来实现现代视觉效果。

        • 不,Swing已相当过时,甚至可能被弃用。虽然我对它很熟悉,但若今天启动新项目仍不会选择它。

          我会用Qt,不过若你不擅长C++,据说JavaFX表现不错。

          • Swing是JDK的标准组件,没有任何弃用内容,甚至还获得了Metal后端支持。

          • 我试过JavaFX,但总觉得回归Swing更顺手——没坏的东西何必修呢。

        • 你邻居的狗对着Swing狂吠呢。

    • JVM及其生态系统也可用于其他语言,比如拥有所有炫酷特性的Scala,还有Clojure等。

    • 我不同意。这完全不符合我的经验。我协助过的每家公司——已有数十家——在迁移到新版JVM时都遭遇了困境。每次都会出现重大问题,需要大量返工和重新测试。我在Java 17或18版本时就放弃了,但这根本无关紧要,因为我合作的团队根本没人真正使用那个版本!2022年某个特别糟糕的项目中,客户因安全需求必须将核心内部系统的JVM从1.5升级,我的职责是评估可行性。很快发现多个关键库早在Java 1.7时代就已停止维护,根本无路可走——它们不过是过时的产品。团队曾尝试获取源代码重新编译第三方jar包,企图掌控代码所有权,但项目范围迅速失控。他们不愿听我提醒:即便升级到1.7版本也会遇到问题。更糟的是,某个路过经理不相信我的评估,竟找来另一人证明我错了。这演变成一场无谓的较劲,令我深感厌恶。那位新加入的同事经验远不及我,却满身傲慢与过度自信。我最终决定终止与该客户的合作——这令人沮丧,毕竟他们是《财富》前十的顶尖企业。据我所知,他们至今未能推进升级计划,仍在使用1.5版本。

      • 是的,这种情况确实存在,但严格来说这与Java无关,而是管理不善的问题。同样的问题在使用TypeScript或C++的公司也可能发生。保持软件安全需要持续维护,包括主动监控第三方库、适时更换库以及进行局部重写。若选择视而不见,妄想在缺乏维护的情况下维持系统运行,最终必将面临彻底重写或付出极高代价才能获得无CVE漏洞的产品。

      • 这必定是讽刺

  3. 新特性:https://openjdk.org/projects/jdk/25/

    Java 25是长期支持版本。

    • 真期待十年后接手将应用从17迁移到Java 25的项目!

      • 我认为从17迁移到25不会太费劲。真正的难关是从Java 8迁移到9+(通常是11),因为引入了模块系统,移除了之前随JDK发布的API(如JAXB)等等。跨越这个门槛后,后续工作就轻松多了。采用17版时还面临另一个通常较小的挑战——反射功能不再像以前那样开箱即用,但据我所知,17版之后没有其他同样颠覆性的变更。

        • 那你还没做过呢。光是这些大公司里所有系统的重新测试就够吓人的了,过程极其复杂。特别是像Kafka这样的实时系统。大多数公司除非万不得已,否则拒绝更新,因为他们把解决方案视为必须产生回报的投资。安全问题在某种程度上改变了这种态度,但你可能会惊讶于通常需要多少返工。在我看来,解决这些问题的挫败感远不值投入的成本——我宁愿另谋出路,所以现在就这么做了。

        • 他说的并非“十年之久”而是“十年之后”,指的是企业升级所需的极长周期

      • 我正带领团队迁移至JRE 25,该版本发布才一天。

        • 我两周后就要实施。我们产品下个重大版本将强制要求JRE 25。

          编辑:我写成“要求”其实是“随产品发布”的意思。我们随产品捆绑发布Temurin JRE,因此每次新安装都会同步更新。

          • 不错!我觉得跟上版本其实不难。现在唯一阻碍升级的因素就是公司自身的文化了。

  4. 构造函数中在调用父类前才允许参数验证和转换,居然花了这么久才实现。

    这点一直困扰着我,因为它违背直觉。

    • 我从JDK 1.0之前就开始编写Java程序,当时这个缺陷就让我很困扰,不过后来我早就学会了绕过它。

    • 尤其因为你总能通过声明一个static函数,并在super的参数中调用它来绕过限制:

      public Foo(int x) { super(validate(x)); }

      validate会在super之前执行——尽管super在构造函数中是第一条语句——编译器对此毫无异议。

      • 这真是个有趣的变通方案,我喜欢。但在任何库或自有代码中都不重要,因为工厂方法更优(仅因它们有名称)。

    • 这在Java 22之前不就可行了吗?

      • > 这不是从Java 22开始就能实现的吗?

        据我观察,多数人只关注Java的LTS版本。这意味着Java 21 LTS之后直接跳到Java 25 LTS。Ubuntu也是同样情况(22.04 LTS之后直接是24.04 LTS)。

  5. (非Java开发者,对此无立场)

    我对模块导入系统不太感冒。import *这类写法虽能简化代码编写,却大幅降低可读性,尤其对语言/代码库新手而言。

    C#和Nim偏爱这种风格,导致没有优质IDE辅助时几乎无法阅读。

    个人更倾向Python的“短别名”风格,例如import torch.nn.functional as F

    • 我始终不理解那些抱怨语言结构“离开IDE就毫无意义”的言论。既然你拥有IDE,那正是你查看代码的地方。那些没有IDE的人纯属自找麻烦,该停止这种行为。在GitHub上浏览代码的人,通常并不需要像追踪引用那样精细地分析代码,而代码的简洁性远比偶尔的困扰重要得多。

      • > 你有IDE吧

        没有。

        某些程序员偏执地拒绝承认这类使用场景:“让我用nano通过SSH写个小程序”,或是“修改一个硬编码变量后直接重编译项目,从此不再碰源代码”。若你的代码离不开IDE才能阅读,这意味着:要么IDE本该作为语言核心组件随编译器捆绑,要么该语言根本就是垃圾——因为其设计者公然承认“我们太蠢解决不了这个问题,只能指望IDE耍点聪明”。

        • 虽然我不认同,但你提出的观点确实有可取之处(远程编辑、修改一行代码后无需再操心)。许多反IDE论调归根结底是“我偏好特定工作流程,并想将其推广到所有场景”——这种立场站不住脚(既然你做了选择,就该付出努力整合,比如让Maven依赖管理与你的超定制Vim环境协同工作)。

          然而,我认为你的论点不足以抵消构建语言平台所能获得的益处——该平台的功能设计本就基于集成开发环境(IDE)支持的存在。

          无论如何,我只是个人观点,你自有主张。

        • 若你认为编译器自带IDE就能消除抱怨,那直接同时安装两者,视作“自带”即可。分离设计源于便利性与选择权,而非开发者愚蠢。安装两个软件对你而言并非难事。

          (既然谈到Java,别忘了当年JRE和JDK下载也采用过类似的分离策略。)

          IDE即开即用确实解决了修改单个变量的场景,但你原本就不需要IDE。这种情况两种方案都可行。

          至于在nano里编写全新程序的场景,我承认其存在但不予采纳。你完全能应付。那些仅出于固执而存在的用例无需特别照顾。IDE只需点击即可启动。

        • > 诸如“让我通过SSH在nano里写个小程序”或“让我修改一个硬编码变量后重新编译项目,此后再也不碰源代码”这类用例。

          1. 此类用例占比微乎其微
          2. 这些程序员往往完全能胜任C++或Rust开发
          3. 更常见的是,他们仅因十年难遇的特殊需求就否定IDE价值,执着于使用次级工具

          • 兄弟连没参与过任何国家安全级别的项目,连尝试提第一种方案的资格都没有。

            • 拜托,你为什么不喜欢这个授权的安全开发流程?就是那个三重嵌套的RDP鲁布·戈德堡装置,通过拨号连接到月球上运行奔腾III处理器的15年前桌面环境(只能运行被时代遗忘的IDE,其中大部分未过时的功能因十八个相互冲突的反恶意软件服务而失效)。

              这套流程可是经过ATO认证的,其他承包商都用着呢。他们按时交付根本不成问题——顶多延迟十年左右;你到底在纠结什么?

    • 在大规模代码库中,导入语句的核心问题在于“这个东西从哪儿来”——你真的需要显式导入。尤其当构建出错时,你无法确定依赖项版本是否正确(该名称对应的依赖项究竟来自哪里)。

      在小型代码库中,任何方式都可行。

      附注:你为何还要关注导入语句?任何像样的编辑器都会将其隐藏,你根本不需要它——直接通过代码中的名称点击/热键导航即可。

    • > C#和Nim偏爱这种风格,导致没有优质IDE几乎无法阅读代码。

      我认为许多人对C#开发体验的抵触,根源在于未使用完整版Visual Studio。VSCode固然优秀,但我绝不会用它打开csproj或sln文件——除非需要手动编辑其XML内容。

      鲜为人知的是,只需500美元即可购买永久版全功能授权软件[0]。无需订阅或其他云端骗局,尽管微软的产品页面初看会让你误以为需要。

      [0] https://www.microsoft.com/en-us/d/visual-studio-professional

    • 据我所知,它主要用于简化单源文件程序的编写。

    • 因此模块导入机制与常规导入不同,实际能减少开发者需要编写的导入语句数量。顺便提一下,Scala(基于Java运行)确实支持导入重命名和类型别名,可以实现你提到的功能。

  6. 该死,结构化并发仍未正式发布。对此功能真是翘首以盼。

    不过看到Scoped Values的加入令人欣喜。这将极大助力在Java中编写我称之为“Rails式”的组件——既避免在万能类中堆砌大量“static final”属性,也无需让万能对象在各处传递。

    • 采用预览机制的做法要好得多,不像如今C++那样在功能标准化时却缺乏具体实现。

    • 希望结构化并发最终能比async/await更简洁高效。现有示例虽未令人信服,但且让我们拭目以待。

      • 结构化部分类似于使用for和while循环替代goto语句——它通过块作用域使并发代码的隔离逻辑更易理解。

        但并发特性依然存在。示例中使用的是未来对象而非async/await,因此线程会阻塞等待其他线程完成。

        Java中替代async/await的方案是虚拟线程。由于它们不属于GC根对象,且栈由堆分配对象链构成,理论上可显著降低小任务的内存开销。编译器无需生成堆对象存储中间状态,直接利用虚拟线程的栈即可。

        然而即使没有async/await语法,仍存在等效概念。由于编译器缺乏原生结构化并发支持,需通过将任务封装在lambda表达式中实现模拟。通过fork()分支子任务,再用阻塞式get()解析未来对象获取结果。但频繁调用fork()、run()和get()未必优于async/await关键字。

        我担心的一点是,Java虚拟线程据说是抢占式的而非协作式的。这意味着在并发修改方面,你获得的保障会比在执行器上协作运行的典型async/await系统更少。一些愿意围绕添加async/await进行更多核心改动的语言,甚至进一步集成了演员模型功能,以帮助开发者编写并发安全的代码。我认为Java在此方面无法像其他语言那样为开发者提供辅助/诊断支持。

      • 遗憾的是在.NET平台上,TPL Dataflow并未获得足够重视。

        • 他们新增的异步通道至少在实际使用中相当出色。

        • 深表赞同。我的使用体验可参考:https://xkcd.com/297/。这可是2012年的东西!那时我甚至还没写过第一个public static void main(string[] args)呢。

          我最欣赏TPL Dataflow的部分是:通过通道+封装实现自定义操作块、背压控制和并行执行,同时保持操作顺序。这是个优秀的库。有时我甚至想,基于通道实现TPL Dataflow 2.0是否可行且有价值。

      • 这看起来比async/await聪明得多

      • 除非他们推出让我愿意放弃ZIO的方案,否则我绝不会动摇。

  7. 我的感觉(仅供参考)是,作为一门老语言,Java在过去十年里不断进步,而C++却每况愈下。

  8. 最近终于下定决心从JDK8迁移

    我们咬牙选择了21版而非17版;其中一个原因是25版即将发布。

    据我观察,最大的障碍是8到11的升级(涉及新模块系统);但之后就一帆风顺了。概念验证是在jdk17上完成的,但直接迁移到jdk21也完全可行(除了guice需要重大版本升级)。

    (当然,使用JVM语言而非Java本身可能也有助益)

    • 对我们而言,从8到17的升级很艰难,因为大量不该使用的旧组件(sun包)被移除。但无数库照旧使用了这些组件。此外,许多组件从javax迁移到jakarta的过程也相当棘手。

      若能熬过这段时期,后续升级将轻松许多。据我观察,升级到21或25版本已相当简单——这些版本主要添加新特性,而长期积压的清理工作带来的重大变革已告一段落。

      我预计今后保持版本更新将变得容易得多。

      • > 对我们而言,从8到17的升级过程相当艰难,因为许多不该使用的旧组件(Sun包)被移除了。但大量库文件依然沿用了这些旧组件。

        据我所知,这些库之所以这样做是因为别无选择,而Java 9及后续版本中的某些变更正是为它们提供了替代方案。唯一剩下的就是Signal/SignalHandler,据我所知,在sun.*包之外仍然没有替代方案。

      • 从javax迁移到jakarta与语言变更其实无关。强烈建议不要同时进行这两项升级。

        • 没错,我知道这是版权问题。

          我们并未一次性完成巨变。先从8版直接升级到17版,随后在独立步骤中升级了需要jakarta变更的Tomcat。

          虽然实际并非如此,但我总倾向于将它们视为一次“现代化”组合升级。

        • 从 javax 迁移到 jakarta 其实与语言变更无关。

          某种程度上有关联;其根源在于Java不再捆绑J2EE库。此前J2EE可视为Java组成部分,如今成为独立项目后,开发者被迫重命名相关包。

          • _JDK_确实不再包含这些包。它们从未属于Java核心组件。

          • 受影响的API均来自名称上明显不属于标准规范的包。

            这些API在特定场景下虽极具实用价值,但始终存在风险——它们可能被以不兼容的方式修改或直接移除。

            • 这无法改变现有代码或JAR文件无法继续运行、必须重写的事实。

              当代码崩溃时,用户不会关心根本原因的细节——它依然无法运行。

              • 该代码从一开始就与标准Java不兼容,因此无人应当感到意外。它本就无法在未实现相同内部API的JVM上运行。

                关键在于,即便OpenJDK项目移除或修改这些内部API,结果也完全相同。但要求甲骨文在此处也维护向后兼容性,纯属不合理。

    • 没错,Java 9堪称生态圈的Python 3时刻,不过相关问题早已解决多年。

      • 两者不可同日而语:Python 3改变了_源代码_语言本身。而对于符合标准Java规范的大多数程序,根本无需任何修改。

    • 是的,你的Java 8代码在Java 9中无法编译,如果使用了因模块变更而被移除或屏蔽的内容——库和运行时都是语言的一部分。

      编程语言不仅包含语法和语义。

    • 就我个人经历而言,最近从17版迁移到21版完全没遇到障碍。一切运行正常,唯一的小问题是同时升级Gradle时出现(但这只是次要问题)

    • 祝你好运。

  9. Java 25新特性精彩概述:https://www.baeldung.com/java-25-features

  10. 过去四年我远离了Java世界,实在怀念。希望很快能重返这个领域。

    这个很酷:https://openjdk.org/jeps/512(JEP 512:紧凑源文件与实例主方法)。它将帮助初学者逐步适应语言,消除语言本身设置的任意门槛。

    我还深入研究了Shenandoah垃圾回收机制的JEP提案,发现它竟是以谢南多厄河谷命名的。超酷。

  11. 令我震惊的是,Java 21中作为预览功能添加的STR字符串模板支持,在Java 23中竟被彻底移除且毫无替代方案。

  12. 当今世界批评Java者必须回答这个问题:若你使用的IDE不提供安全的“提取方法”功能,那么你的语言基本就是垃圾。

    • > 若你使用的IDE不提供安全的“提取方法”功能,那么你的语言基本就是垃圾。

      这为何是语言问题而非IDE问题?

  13. 欣喜看到“向量API(第十孵化器)”——它将为Java机器学习工具包亟需的底层向量运算开辟可能性。

    • 其实这也不是什么新鲜事。大概只有在值类型出现后才会被冻结。

  14. 从法律角度看,当前使用Java的现状如何?在开源和商业场景中?甲骨文将许多卓越技术锁定在Java中(比如Truffle),这对新项目来说合理吗?

    • OpenJDK 基本完全开放,直接来自甲骨文。

      若您不喜欢甲骨文(我完全理解),还有其他选择:从 Eclipse 基金会到微软、亚马逊等机构都提供了功能相似的替代方案。

      至于新项目,Java 仍将长期存在。其生命力正是企业仍在使用 Java 8/11 的原因之一——一旦编写完成,程序几乎能永久运行。

      虽然在特性方面落后于几乎所有竞争对手,但其功能足以完成任何重要任务。

      若你依赖JVM,我个人会推荐Kotlin(主要因为Java至今仍缺乏可空类型,导致空指针异常无处不在);若不喜欢Kotlin语法,C#也是选择。但Java本身已足够优秀。

    • 当前真正的棘手问题在于:若使用Oracle发行版,仅最新LTS版本实质上可自由使用。

      旧版本受OTN许可约束,仅限个人开发用途,禁止用于生产环境。

      再次强调,这仅在您希望在运行时环境上贴上Oracle标签时才重要,OpenJDK及其他项目都是完全自由的JDK。

    • 完全无需担忧。OpenJDK是完全开源的。

    • Truffle不属于OpenJDK项目。它是独立项目,采用通用许可协议授权:https://github.com/oracle/graal/tree/master/truffle

      UPL是经OSI认证的开源许可证。在任何场景使用都不应有问题,但建议咨询法务团队确认许可范围。

    • 使用OpenJDK(或类似项目)即可完全规避Oracle的各种限制。

      • 我并非反对(毕竟它采用GPL许可)——但需谨记OpenJDK同样由甲骨文提供。

        所有其他变体最终都只是重新打包。因此若甲骨文无意维护Java知识产权,完全可能切断所有后续更新渠道。

        不过我认为他们不会这么做,MySQL至今仍可自由使用,对吧?那也是甲骨文的知识产权。

        若他们陷入财务困境或许会改变,但所有语言和框架都面临同样问题。

        • 还有Amazon Correcto、Eclipse Temurin…

          当然,他们可能停止维护,但分叉项目会立即让其他公司掌握主导权

          话说回来,甲骨文向来贪得无厌…

          • > 当然,他们可能停止维护,但分叉项目会立即让其他公司掌握主导权

            我感觉所有相关公司/组织会联合起来共同维护。

          • Amazon Corretto和Eclipse Temurin由甲骨文开发并授权,仅分别由亚马逊和IBM进行打包分发。若向它们提交问题报告,亚马逊/IBM人员会将问题转交甲骨文处理。

            顺便说一句,我不否认甲骨文的贪婪,但认为亚马逊、IBM、谷歌、微软等公司更不贪婪的提议实在可笑。

        • 坦白说,Java是少数让我完全不必担忧的技术之一。

          它无处不在。仅FAANG企业中,苹果、亚马逊、奈飞和谷歌就必然大规模使用它,而这只是冰山一角。若停止JVM更新,对这些企业而言几乎等同于灭顶之灾——即便甲骨文倒闭,它们也绝对有能力维持Java的生存。

    • 这仅在您计划编写自有Java实现并进行分发时才需考虑。

  15. 我认为部分企业客户或许该考虑升级至Java9了?

  16. 瓦尔哈拉项目至今仍未完成实在令人扼腕。它能解决诸多问题,并为Java提供更强大的矩阵运算支持

    • 我第一次听说Valhalla是在2014年(记忆无误的话),距今已逾十年!但我对Java的工程设计深感满意。如此精心打磨的技术实属罕见。若追求长期稳定性,Java正是你梦寐以求的技术。

    • 瓦尔哈拉项目规模庞大,不可能仅通过一次发布就全部落地。即便表面语言和JVM的所有变更都已实现,新增优化功能也才刚刚起步。

    • 该提案两周前才提交,未来版本中或许还能看到新进展。

  17. GraalPy当前进展如何?

  18. 是否已实现泛型实例化?

  19. 我认为部分企业用户或许该考虑升级到Java9了?

  20. 不,谢谢。我整个职业生涯从未碰过Oracle产品,这永远是我的第一准则。

    • 那谷歌、Meta和微软呢?

      • 是的。二十年前我就决定永远不碰也不学Oracle产品。这样做有错吗?没有它们我的职业生涯照样顺风顺水。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注


京ICP备12002735号