2026:Java 的命令行元年
命令行终端不仅是快速脚本的舞台——更是开发者每日使用的强大交互式应用载体。Java完全有能力参与这场变革。
听着,我要说的话可能让某些人觉得疯狂:Java理应在命令行终端中表现得更好。而2026年?那将是解决这一问题的关键之年!
最近我目睹人们对AI命令行终端应用的惊叹之情。这些基于大型语言模型的命令行工具能协助编写代码、解答疑问、生成内容——所有操作都在命令行终端中完成。但你们知道它们是用什么语言编写的吗?Python、Rust、Go、Node.js——唯独没有Java。
与此同时,数百万Java开发者正苦苦思索:是否需要学习Rust或Go才能在命令行终端打造酷炫工具?其实不必。
关键在于:没有任何因素阻碍我们用Java实现完全相同的工具。真的没有。我们拥有HTTP客户端、JSON库、流式API,所有必需组件一应俱全。唯一缺失的,是我们对Java属于命令行终端环境且能完美适配的信念。
太久以来,我们默认着这样荒谬的现实:Java无处不在——支撑着庞大的企业系统,驱动着安卓应用,处理着海量交易——但当涉及快速CLI工具、脚本编写或命令行终端调试时,多数Java开发者却转向Python、Node、Go,甚至干脆放弃行动。这种现状必须改变。
为何是现在
所需工具已基本齐备:PicoCLI 擅长参数传递;Project Loom 提供虚拟线程实现轻松并发;GraalVM 原生映像持续优化加速;JBang 让运行 Java 脚本如 Python 般便捷;JBang 与 JReleaser 解决所有分发难题。Java 平台及其生态已臻成熟,昔日的借口再难成立。
还记得我们曾说“Java启动太慢”吗?
试试现代Java运行时。它并不慢。
试试GraalVM原生映像。毫秒级启动。瞬间完成。
“Java工具链太臃肿”?现代Java搭配jshell、单文件源程序和JBang等工具,轻量化程度随心所欲。
“Java过于冗长,不适合快速脚本”?JBang让你只需编写单个.java文件,在顶部声明依赖即可立即运行。无需构建文件,无需繁文缛节,纯粹代码。JBang兼容任何Java版本。
“分发太复杂”?JReleaser自动化整个发布流程——GitHub发布、Homebrew源、SDKMAN、Docker镜像、原生包,应有尽有。
那些你常拿来开脱的借口?早已过时。你以为了解的Java,早已不是如今的Java。
但等等——这不仅关乎脚本
真正精彩的部分在于:我说的绝非用Java替代bash脚本。我指的是构建真正的命令行终端应用程序。就像你在Rust生态中看到的ratatui那般精美的TUIs,或是Python的textual,又或是Go语言中Charm的Bubble Tea。
仔细想想:为什么命令行终端UI应用必须是其他语言的专属领域?几十年来我们拥有Lanterna和Jexer,却始终未能真正进入主流。如今Jexer在Casciian分支焕发新生,甚至已有Latte开始移植Bubbletea。构建非凡之物的基石已然就位。
想象一下:仪表盘、文件管理器、日志查看器、监控工具、支持丰富格式的AI聊天界面——所有这些都拥有精美的命令行终端界面,全部用Java编写,借助原生映像快速运行,并充分利用整个Java生态系统。
我们需要属于我们的 《料理鼠王》时刻 。
我们需要属于我们的 文本版 。
坦白说?根基早已奠定。我们只需推动它向前,让它更易用,让它更美观。
这不是竞争——而是互补
请明确:这并非要削弱Rust、Python、Go或其他生态中正在发生的卓越工作。这些社区在命令行终端工具领域创造了非凡成就,我们应当为此喝彩并汲取灵感。
我们的目标是让Java生态意识到:他们同样能轻松——甚至更出色地——为命令行终端工具世界添砖加瓦。数百万精通Java的开发者深谙语言特性、熟悉生态体系,本可打造卓越的命令行工具和图形化命令行终端界面,却误以为必须先学习Rust或Go。
其实不必。
你已精通Java,更掌握构建工具的诀窍。别因误以为Java“不支持命令行终端”就另寻他途——它完全可以做到,只是你尚未尝试。
命令行终端工具生态因多样性而受益。不同的工具、不同的方法、不同的生态系统都在贡献力量。Java开发者带来了独特的价值:庞大的库生态系统、久经考验的并发原语、企业级可靠性,而现代Java更具备媲美任何平台的性能与启动特性。
我们并非试图取代任何东西。我们致力于拓展可能性边界。更多工具。更多选择。更多开发者共同参与,为所有人打造更卓越的命令行终端体验。
JBang革命
让我们深入探讨JBang的本质,因为许多人尚未洞悉其真正潜力。
没错,JBang运行单文件Java脚本。但它的价值远不止于此。
从Gradle或Maven构建中得到一个臃肿的JAR文件?只需执行jbang myapp.jar即可运行。
想直接运行Maven Central上的项目?输入jbang group:artifact:version,JBang会自动下载并运行。
需要自定义Java参数来提升性能或加载原生库?JBang同样能轻松处理。
这正是我们一直缺失的分发模式。
简单命令行工具无需Docker容器,无需复杂安装指南,更不必担心用户Java版本不匹配——JBang连这都能搞定。
“我的工具在此:jbang app@myuser/myrepo`”,或直接`jbang org.example:mytool:1.0.0从Maven中央仓库运行。
搞定。这就是全部安装说明。JBang会自动下载、解析依赖并运行工具。
如今让大多数Java应用在他人机器上运行已轻而易举。
真正可用的分发方案
但更精彩的还在后头。你知道过去最头疼的事是什么吗?发布Java命令行工具。创建GitHub发布版本。为多平台构建原生镜像。对接包管理器。编写Homebrew公式;接入SDKMAN分发。
JReleaser应运而生。
JReleaser将所有繁琐流程转化为配置项。只需描述需求——Linux/macOS/Windows原生镜像、Homebrew分支、SDKMAN分发、Docker镜像等——JReleaser自动处理。单条命令即可将发布版本推送至所有渠道。
现在你可以构建Java命令行工具或文本界面工具,用GraalVM编译为原生映像,再由JReleaser分发至所有平台。Mac用户可执行brew install your-tool,Linux用户可通过SDKMAN或原生包获取,Windows用户则能获得安装程序或Scoop包。
突然间,分发Java命令行工具变得和——不,比其他生态系统更简单。而你拥有整个Java生态系统作为基础。
命令行终端中的Java真实面貌
我所说的“需要Java”场景包括:
- 解析API返回的JSON数据并进行转换
- 快速构建自动化任务的命令行工具
- 编写需要完善错误处理的一次性脚本
- 创建全团队可轻松安装运行的实用工具
- 快速原型开发、便捷共享并后期扩展
- 发布专业级CLI工具,支持用户通过常用包管理器安装
- 构建精美的TUI监控仪表盘
- 开发命令行终端运行的AI智能助手
妙处在于这些“快速脚本”和工具能持续成长。那段20分钟写就的代码?当它需要升级时,你已在Java生态中游刃有余——拥有类型安全保障、IDE支持、测试框架及完整生态系统。无需用“真正”的语言重写,因为它本身就是真正的语言。
别再认为Java只适用于“严肃”应用。它同样适合当下急需的快速脚本,适合周末想搭建的TUI界面,也适合团队下周急需的命令行工具。
前进之路
实现这一愿景需要:
构建TUI生态系统。 我们需要凝聚命令行终端UI库的开发力量。为它们贡献代码,提升易用性,打造令开发者惊叹“哇,我想要这个”的示例。
分享更多实践案例。 当你在命令行终端用Java解决问题时,写博客分享,发推文传播。向世人展示这不仅可行,更令人愉悦。开发TUI时录制演示视频,尽情展示成果。
借助JBang和JReleaser分发。 让你的命令行工具和TUI支持JBang运行以快速测试,再通过JReleaser将其推送至Homebrew、SDKMAN及原生包管理器。让安装变得如此简单,无人能拒绝尝试。
拥抱原生映像。 对于需要快速启动的工具,请投资GraalVM原生映像。虽然反射配置存在学习曲线,但回报真实可观。而JReleaser能让多平台构建变得轻而易举。
推广单文件Java程序。 并非所有项目都需要Maven项目结构。有时脚本就是脚本,这完全没问题。
善用框架。 诸如我最爱的Quarkus、Micronaut、Spring Boot等框架已具备强大的命令行支持,极大简化了原生映像编译流程。它们能构建从小型工具到完整应用的各类项目——在此实现命令行终端用户界面(TUI)理应轻而易举。
突破边界。 打造雄心勃勃的作品。用Java打造文件管理器。开发拥有炫酷TUI的系统监控器。构建具备丰富命令行终端界面的AI编码助手。创造让jq相形见绌的日志分析工具。展现无限可能。
核心要义
Java本就是拥有庞大生态、卓越性能与坚如磐石可靠性的非凡语言。我们却长期忽视了它在某个领域的天生优势——命令行终端应用开发。
命令行终端不仅是快速脚本的舞台——更是开发者每日使用的强大交互式应用载体。Java完全有能力参与这场变革。
当更多生态系统加入,命令行终端工具的世界将更臻完善。我们并非来竞争,而是来贡献力量。贡献独特的优势与视角,为所有人打造更丰富的命令行终端体验。
2026年,我们将改变现状。工具已就绪,语言已就绪。JBang让分发变得轻而易举,JReleaser让专业发布触手可及,原生映像实现瞬间启动,虚拟线程让异步编程优雅流畅。我们只需转变思维,开始构建。
谁愿与我同行?
去编写基于Java的工具吧。打造图形用户界面。让它们真正实用。让它们赏心悦目。用JBang分发它们。收集反馈,持续迭代。最终通过JReleaser正式发布。让我们向世界展示命令行终端中的Java能创造何等可能。
坦白说?我们沉睡得太久了。是时候醒来了。
敬请期待——让我们在2026年尽情享受吧!
本文由 TecHug 分享,英文原文及文中图片来自 2026: The Year of Java in the Terminal。

除非构建打包成为头等大事,否则Java永远无法成为命令行工具领域的玩家。Go、Rust等语言之所以普及,正是因为它们的构建工具极其简单。只需一条命令就能轻松生成单文件可分发包:go build、cargo build、dotnet publish——完全自包含。
而Java却无法生成单一可分发包。无法将jar文件与虚拟机打包成二进制文件。虽然可使用Graal Native Image,但构建耗时极长、资源消耗巨大,且实现过程复杂。
Java生态的构建工具体系终究不够完善。
> 除非构建打包成为核心功能,否则Java永远无法在命令行工具领域占据一席之地。
Python打包历来痛苦,但它仍是CLI工具的热门选择。
技术选择不仅关乎理性,更承载着文化与教条。
Python的反例极具说服力。许多语言通过将程序痕迹“隐藏”在/usr/local或虚拟环境中实现“眼不见为净”。
JVM安装干净且自包含,但默认情况下任何构建产物都不共享至系统范围——这始终被视为安全风险。如今的热词是“供应链攻击”。
相反,大多数Java程序拖拽着依赖项,给人臃肿之感:所有内容都赤裸裸地呈现在眼前,以你用户身份存储并运行。
我深知Python在该领域的主导地位远早于uv诞生,但uv([https://docs.astral.sh/uv/](https://docs.astral.sh/uv/))让Python打包对我而言变得极其简单
我认为uv并未简化发行流程?除非我理解有误,它开箱即用时并不能帮助生成独立可执行文件——虽然能构建轮子包,但这些仅对已安装Python和pip的用户有用,且无法解决Python版本漂移等问题。
uv不仅能拉取锁定文件指定的库版本,还能安装你选定的Python版本。这套方案对新手极其友好。
没错,但这意味着终端用户必须拥有(或安装)uv,然后你把所有代码交付给他们,他们才能用uv运行程序。这属于开发工作流范畴——也正是我所指的:uv并未像Go或Rust这类语言通过生成单一二进制文件那样解决分发问题。
uv并非万能解药,但它确实大幅提升了Python工具的运行成功率。
jbang之于Java,正如uv(x)之于Python,npm/npmx之于JavaScript。
若使用pyinstaller[1],Python打包难度其实不比Rust、C#或Go更高。
只需执行“pyinstaller –onefile –noconsole main.py”,即可生成单一可执行文件。
[1] [https://pyinstaller.org/en/stable/usage.html](https://pyinstaller.org/en/stable/usage.html)
“Java无处不在”曾是JVM的核心卖点,如今却颇具讽刺意味。但如今它甚至未被默认包含在macOS中,因此若想让他人使用你的Java/clojure命令行工具,对方必须先安装Java。这难免令人侧目,让人不禁质疑“这是什么年代?2010年吗?”
jpackage
它能自动完成所有工作,作为标准工具可生成平台专属的应用程序包。
真正活在2010年的人,是那些选择固守陈旧观念却又对事物一知半解的群体。
将JRE打包到应用程序中通常会导致无法在默认OpenJDK许可证下重新分发:Java生态系统普遍采用Apache许可证,但Hotspot仅采用GPL v2许可证(无类路径例外条款)。Apache许可证与旧版GPL(3版之前)通常被视为不兼容。
所有现代OpenJDK构建均采用GPLv2+类路径例外许可。该例外涵盖Hotspot,因其属于JVM组成部分。此豁免允许将JVM与应用程序捆绑分发或进行链接,否则众多企业软件将无法存在。
此说法不准确。
即便Eclipse和IntelliJ也随发行版捆绑基于OpenJDK的运行时,且其GPL限制更为严格。
jpackage是否已更新为创建非安装程序且不自动解压为多个文件的打包形式?
你问的是本质不同的概念。
应用程序包(.app、.rpm、.deb、.msi/.exe等)是jpackage能为你构建的产物,它们是包含JRE的单一可交付工件,用户无需额外操作。其设计初衷就是方便分发Java应用程序。
若需完全静态链接的二进制文件,你需要深入研究GraalVM和native-image:[https://www.graalvm.org/latest/reference-manual/native-image…](https://www.graalvm.org/latest/reference-manual/native-image/)。这将实现你的目标——本质上就是可通过wget下载并执行chmod +x的文件。
我并非在探讨本质不同的概念。其他语言的成功并非源于它们能生成安装程序。你尝试过用native-image构建非简单应用吗?我从它发布之初就一直在使用,是Windows平台上Quarkus框架采用native-image的首批实践者,当时甚至参与编写了相关文档。实际使用并不简单,编译耗时极长,所需资源有时甚至超出开发者机器的承载能力。
每次尝试用Native Image处理超过基础Swing应用的项目,都简直是场噩梦。
> 平台依赖性
写一次,到处跑。
java -jar
或用Graal构建Native Image后分发。
但这并非用户所需。他们想要的是.exe、.app、.rpm等格式——这些容器封装了.jar文件,且具有平台特异性,此问题无解。
OpenJDK也大幅削减了操作系统支持,如今基本仅限于Windows、Mac和Linux。以及AIX。
不再支持FreeBSD、Solaris、开源Solaris(illumos smartos等)。
甲骨文停止分发JDK并不等于不可能实现。任何人都可以挺身而出完成此事。
[https://github.com/psumbera/solaris-openjdk](https://github.com/psumbera/solaris-openjdk) 似乎可行?
我从未说不可能,只是指出他们终止了支持。
明白了,但实际影响是什么?
其他运行时环境难道不是同样由单一厂商/项目提供有限支持吗?
Java因甲骨文的决策遭受重创…他们至今仍提供指示用户另行下载的Java可执行文件实在令人恼火——但你该知道苹果早在2024年就从Mac系统移除了Python,且从未分发过Python3版本吧?
那么Python会因此被淘汰吗?
不会,因为生态系统并未消沉,而是持续运作并填补了空白。
Java生态也做了大量类似工作——但大众仍固守着旧有认知。
让我们改变这种局面吧 🙂
GraalVM原生二进制文件?
在甲骨文不再构成威胁前,Java永远不该参与任何重要领域。甲骨文只想寄生在真正创造价值的企业身上。
甲骨文接管时我就放弃了Java,当时觉得这是场灾难。但必须承认,他们(暂且)没毁掉整个生态
他们维持了Java的生命力,允许其发展创新,甚至让绿色线程重返舞台。
我虽无意回归Java,但这已不再是针对甲骨文的抗议。
在我看来,甲骨文比Sun更胜任Java的守护者。当初我从未预料到这般局面,但结果还算不错。
微软提供OpenJDK发行版的做法值得肯定。毕竟在Windows系统上使用更值得信赖,有什么风险呢?
[https://www.microsoft.com/openjdk](https://www.microsoft.com/openjdk)
谷歌比甲骨文更具威胁性。
为何如此?我从未见过雇主或客户因谷歌而面临诉讼威胁。
我曾在几家初创公司工作,它们主要基于Java开发并拥有多个命令行工具。核心工作是构建“胖jar”文件,然后通过“java -jar …”命令运行,或执行实现此功能的脚本。Java虚拟机是系统依赖项,将其直接封装进二进制文件根本不现实。
我在一家初创公司工作,需要向客户交付Java命令行工具。这简直是头大麻烦。用户频繁因Java版本问题(过旧或过新)提交支持请求,有时甚至要等上数周才能获得安装Java运行时的授权。IT部门对安装Java的要求极其严格。
我能理解这种困扰。我之前负责内部应用时,所有基础设施都由我们管理。但有些IT部门对安装任何软件都极其严格,甚至要求所有网站访问都必须通过ZScaler这类代理工具。
没错,被收购后我们自己的IT部门连ngrok都不准用,尽管工程部门已支付了许可费用。
> IT部门对安装Java极其严格。
可以理解,毕竟某些Java运行时环境(最典型的是甲骨文的版本)要求商业用途必须购买付费许可证。让用户安装这类软件可能使公司陷入法律纠纷。
截至2021年,部分版本确实要求商业用途购买付费许可证,而甲骨文的某些Java版本仍可免费用于商业用途。
或者效仿全球主流做法:使用Eclipse Adoptium(我认为这是最佳JDK)或OpenJDK、微软等提供的版本。
你和那位家长再拿甲骨文Java许可问题说事已不合时宜。现在不是2009年了。
关键在于法律风险:员工自行下载JRE存在隐患——虽然下载Adoptium可能无虞,但若误下载需商业许可的版本呢?IT部门绝不会容忍这种风险。
> 反观Java,它根本无法实现单一可分发版本。
噗,这实在令人哭笑不得又充满讽刺——毕竟“写一次,到处运行”可是Java的立身之本,结果却惨败收场。
它确实成功过一段时间。Java小程序曾相当普及。但后来Flash基本取代了它们,随后HTML5彻底终结了它们。
虽然“任何地方”的适用范围极其有限,但确实存在过。
针对这种使用场景,无论是动态内容、中间表示形式传输还是沙箱环境,Java的表现都极其糟糕。
这篇文章(你可能没读过)特别提到了使用JBang[1]实现此目的。
[1] [https://www.jbang.dev/](https://www.jbang.dev/)
Max在/r/java分享时我确实读过。JBang解决不了你想象中的问题。
实际上它可能确实能解决。不过我更期待Java能发展到能实现这些第三方项目功能甚至超越它们的阶段。
在任意AI中输入以下提示,尽情与AI辩论你的观点:“jbang解决了什么问题?”
你认为jbang在这方面未能解决什么?
我并不认为“单一二进制文件”在实际应用中至关重要。真正关键的是应用程序的安装、运行和更新便捷性,而这完全取决于目标用户群体。
对于终端用户应用,这个问题基本已解决:使用jpackage打包可安装应用,内含精简版JRE。更优方案是通过操作系统应用商店分发,更新由平台自动处理(在Linux系统中,Flatpak可能是当前最佳选择)。
对于命令行工具,开发者已默认面向技术用户群体。此时存在两种可行方案:
– 提供完整打包版本(Go/Rust静态二进制、pyinstaller、jpackage)
– 仅提供应用本体,依托智能启动器/运行时管理器(npx、bunx、uvx、jbang),并假设技术用户能先行安装这些工具
真正的核心问题并非“是否为单一二进制文件”,而是“用户如何安装、运行及更新程序”。实际上,开发者包管理器如brew和Scoop早已解决此问题。我机器上的所有Go和Rust命令行工具均通过brew安装,而非手动从GitHub发布版下载。
此外,CLI工具需置于PATH环境变量或开发环境(如mise、direnv等)中,因此可执行文件是真正单一二进制文件还是指向打包程序的符号链接,其实并无本质区别。
因此核心取舍在于:是支持带捆绑JRE的`brew install foo-java-tool`,还是要求用户先执行`brew install jbang`再执行`jbang install foo-tool`?无论哪种方式,最终结果都是运行`foo-tool`。
需注意,例如 Claude Code 同时支持两种方案(curl | bash、brew cask 和 npm -i),它并非单一二进制文件,但这并未阻碍它成为今年/去年最受欢迎的 CLI 工具。
Java 的打包方案确实存在改进空间,但我认为重点不应放在“单一二进制文件”作为首要目标上。
> 无法将jar文件与虚拟机整合为单一二进制文件。
我的文本编辑器KeenWrite[1]曾提供Linux、macOS和Windows版本。Windows二进制文件因代码签名成本及第三方构建需求被取消,而非跨平台打包的技术问题。
一种方案是使用warp[2]等工具创建自解压可执行文件。我编写了安装脚本[3](install.sh)来生成平台专属启动器。在Linux上运行`time keenwrite.bin –version`耗时0.327秒;首次运行后后续启动极快。
[1]: [https://keenwrite.com](https://keenwrite.com)
[2]: [https://github.com/kirbylink/warp](https://github.com/kirbylink/warp)
[3]: [https://repo.autonoma.ca/?action=repo&repo=keenwrite.git&vie…](https://repo.autonoma.ca/?action=repo&repo=keenwrite.git&view=tree)
[https://docs.oracle.com/en/java/javase/17/docs/specs/man/jpa…](https://docs.oracle.com/en/java/javase/17/docs/specs/man/jpackage.html)
这并非易事,无法与标准构建工具兼容,且除非情况有所改变,否则生成的安装程序会解压为多个不同文件。你无法直接获得可交付的独立静态链接二进制文件。
将jar文件与虚拟机封装成单一二进制文件似乎是个可解决的问题。
自从使用GraalVM并创建jbang后,我对应用程序+JVM的组合已无迫切需求——现在运行应用程序+共享JVM对我而言轻而易举。但我能理解这种组合的实用价值。
已记录各项参考资料及现有尝试,计划在2026年深入探索!
关于构建与发布——我认为这同样可解决。
尤其当我们不再试图适配所有可能的Gradle/Maven构建变体,而专注于让JAR文件正常工作时…这正是jbang/jreleaser真正简化流程之处,其价值远超多数人认知。
因此2026年我必将发布更多相关实践方案,并探索实现类似`jbang publish`的“开箱即用”功能。
没错,我们在Reddit讨论过这个。我认为并非不可能,只是需要付出努力!
我深信这符合“铺设上坡道”的理念。让构建工具成为核心且简洁的组件,将有效推动其普及。
Maven构建胖JAR文件有什么问题吗?
问题在于它不支持动态链接——尽管历史版本的Java对极晚绑定有出色支持。(新版本需要特定启动器配置才能使用某些平台特性,这会破坏使用这些特性的类在运行时的加载机制。)
>无法将jar文件与虚拟机打包成二进制文件。
GraalVM原生映像恰恰实现了这一点。只需添加单个Gradle插件即可轻松实现。
没错,连JS都比这更适合命令行——直接npm安装即可。其分发方式也带来巨大差异。
jbang install 功能相同。还不够吗?
我从未接触过它。我从未用过jbang安装的工具,相信不止我一人如此。
多数开发者都安装了npm,虽然我不喜欢它,但它确实能高效将软件部署到开发环境。
没错,现在你知道它的存在了——试试看吧 🙂
而且它同样兼容npm、uvx等环境。
`npx @jbangdev/jbang`
这不正是模块和jlink的功能吗?
我曾长期关注JVM启动时间和命令行适配性(20多年前开发nailgun[0],不久后又开发jsap[1]正是为此),如今看到技术进步如此之大实在令人惊叹。现代JVM启动速度和GraalVM原生映像技术已消除了大部分旧有借口。jlink+jpackage极大简化了分发流程,而JBang则将效率提升到全新高度。虽然用过JBang,但这篇文章仍让我学到新技巧。坦白说,它简直就是JNLP/WebStart本该进化的形态。
我认为强制用户预装JBang并非最佳推广策略。但若能构建原生包——在需要时自动加载JBang并生成启动器/桌面快捷方式——这似乎是更自然的方案,或许还能成为有趣的项目。
在终端用户界面领域,Java亟需像Go语言的Charmbracelet[2]那样直观美观的解决方案。当开发者在实际应用中频繁见到出色的Java终端界面时,他们的认知必将改变。
工具链已然就位,或至少近在咫尺。当前阻碍Java在终端领域发展的,主要是那些过时的固有观念。
[0] [https://martiansoftware.com/nailgun](https://martiansoftware.com/nailgun)
[1] [https://martiansoftware.com/jsap/](https://martiansoftware.com/jsap/)
[2] [https://github.com/charmbracelet](https://github.com/charmbracelet)
巴巴什卡摸着下巴沉思…嗯…
编辑:嘿… [https://rattlin.blog/bbgum.html](https://rattlin.blog/bbgum.html)
这思路很酷!
为什么?它根本不适合——语言语义本质上导致庞大的分布式架构、缓慢的启动速度,还需依赖机器上的运行时环境。好吧,听说Graal能解决这些问题,但这本身就是另一层复杂性,而用Go这类语言编写的工具就完全不必担心这些。
Python也有类似特性,但至少我能理解它作为“优雅”语言的价值。Java从来不是我的首选,更何况面对如此高耸的技术门槛时就更不考虑了。
我根本不同意文章里那些“必须改变”的论调。我认为根本不需要改变。比起Java,我更希望人们用Go或Rust编写命令行界面——后者对我来说绝对是痛苦的体验。
使用那些每年都在重大更新的编程语言的过往经验来评判未必公平。对我而言,Java作为命令行环境相当顺畅,尤其是Saxon。只需给命令设置别名并包含JRE二进制文件的路径即可。
Python就痛苦多了 🙂 当然不是针对Go,毕竟为系统构建二进制文件才是最省心的。
关于启动缓慢的问题,我认为这在任何场景下都同样适用于Python等语言。过去15年里,JVM启动时间从未实质性影响过我的工作流程。
原因在我看来很简单:我看到Java开发者为这类需求转向其他主流工具,却因引入仅凭惯例“要求”的新语言而自找麻烦。我渴望看到丰富的Java TUI/CLI库生态,以便复用现有业务逻辑和公司库。目前唯一的障碍是缺乏高度优化的封装工具。在我的工作环境中,这将是非常有价值的补充。
没错,正如我所说,Python在启动时间方面也存在类似问题。
我接触过的Java命令行工具有限,最明显的例子是Gradle这类工具——操作起来总感觉迟钝,连基础操作都要2秒以上实在令人恼火。虽然不算世界末日,但相比那些响应迅捷、设计精良的系统,这种体验显然不够理想。
恰巧我已开发出解决方案:TUI4J(Java终端用户界面)。
[https://github.com/WilliamAGH/tui4j](https://github.com/WilliamAGH/tui4j)
它融合了Go语言实现的BubbleTea移植版,以及Textual等工具启发的功能重构。
这是对早期项目的分支,我致力于扩展并稳定其功能。
我打造了一个极简美观的LLM聊天界面,具备完整对话窗口、动画效果,并实现键盘鼠标交互的完全对等支持,充分展现了这个Java库的潜力。
示例聊天应用:[https://github.com/WilliamAGH/brief](https://github.com/WilliamAGH/brief)
期待看到大家用它实现类似功能!
直到读完子目录中的环境变量API密钥文档,我才明白简报的含义。我觉得不该用“这是tui4j应用!”和“这是终端聊天!”作为开场白。它本质是终端版的OpenAI ChatGPT接口。既然这是展示演示库的宣传,附上截图也不失为明智之举。
两个建议都很棒 🙂
没想到我正在开发的主题今天就登上了Hacker News封面,确实有点措手不及,不过这些功能绝对是接下来待办事项清单上的重点!
厉害——你藏得真深,我找了半天都没发现。
绝对要去试试。
…brief的jar包在哪儿呀? 🙂
我调整了Github发布配置,现在你也可以这样操作:
curl -L -o brief.zip [https://github.com/WilliamAGH/brief/releases/latest/download…](https://github.com/WilliamAGH/brief/releases/latest/download/brief.zip)
unzip brief.zip
cd brief-*/
./bin/brief
不错——但我其实更希望提供Maven坐标或.jar文件,那样就能直接用jbang运行了 🙂
啊——原来tui4j是latte的延续。明白了,难怪看起来这么相似。太棒了!
希望你喜欢tui4j和brief!
终端程序的启动时间不该成为问题。我写过相当复杂的Java、Rust和C++终端程序,它们的运行时基本没差别。多数人觉得Java启动慢,是因为在运行Spring框架的Web应用,带着50个依赖项加载Tomcat,而不是单纯启动JVM执行几个函数。
获得即时编译(AoT)的Java程序堪称救星。执行`java -jar main.java -foo -bar`既烦人又不够友好,必须打包成工具包才能实现`tool -foo -bar`的便捷操作。
+1 支持即时编译。令人惊讶的是,即便剔除所有冗余组件,Graal与“标准”JVM仍存在显著差异。两者都完全可用,但后者确实给人“瞬间启动”的体验。
初次尝试Graal时我惊叹不已,但转念想到这或许正是C/C++或Rust开发者习以为常的常态。
作为拥有二十年经验的Java开发者,我用它做过从前端到分布式系统的所有项目,用Java构建过Gradle插件和命令行工具,甚至能背诵IntelliJ里所有快捷键。
即便如此,我配置Go/Python/TypeScript命令行工具所需的时间仍远少于Java。Java命令行工具简直是为解决不存在的问题而生的方案。
我也差不多。有个Java项目已经持续开发了十多年。它是一组日常工作中使用的实用工具集合,这些年规模不断扩大。这是个命令行程序,运行在我的Mac、Linux服务器和Linux高性能计算集群上。它采用胖JAR打包,前面连接一个shell stub,实现单文件安装。我还编写了一个完整的命令行程序定义库。它使用起来相当简单,但依赖反射和注解机制,因此Graal的适配一直很棘手(至少上次尝试时如此)。
以上所述,说明我也深谙此道。
过去三四年间,我更倾向于用Go语言开发新CLI项目。集群间安装的Java版本细微差异虽是问题,但对我而言最大的困扰在于处理JVM参数。我编写的代码用于处理基因组数据文件,这些文件时而庞大时而微小,而我厌恶必须同时告知作业调度器(如今主要是SLURM)和JVM使用多少内存。
Go语言完全规避了这个问题。因此它自然成为我如今的首选语言。
> Java命令行工具是为解决虚构问题而生的解决方案
这句总结得真到位。我也是Java开发者;我最熟悉Java,甚至可以说我喜欢Java。但若要开发命令行程序,Java绝对排在我的工具清单末位。
我曾与你感同身受——直到创建jbang项目,因为实在厌倦了看到Kotlin脚本被用来编写Java代码…
后来当我能编写带依赖的Java脚本时,我们实现了JDK自动下载功能,进而支持运行任意JAR文件(不仅限脚本)。如今我对所有操作都拥有完整的调试支持,还能在 *任何* Docker容器或笔记本上安装运行——即便是父母家或图书馆那台古董Windows电脑也不在话下。试试看用npm和Python实现这个吧 🙂
我想表达的是——我理解你的顾虑。但至少近五年(过去三年半尤为明显),已有比Python/NodeScript/TypeScript更便捷可靠的方式利用JVM…无论是运行命令行工具、Swing/JFX界面,还是后端应用。
而到2026年,我要让Java TUI成为现实。
同感。从Java的alpha/beta/gamma时代就开始使用,用它构建过大量项目。但不会默认用它做命令行工具,除非它恰好是最简洁的选择(比如某个库几乎能完成所有需求)。
或许关于启动时间等旧观念已不再成立,编程模型也不再像从前那样冗长。但我绝不愿分发200MB+的二进制文件。同事们总夸C#脚本多么强大——只需安装.NET或用AOT编译即可。恕我直言,Go和Rust固然优秀,但Python脚本的体积更小,且比我见过的多数语言强行塞进的解决方案更易读易写。我对Java并无偏见,但它并非解决此问题的正确工具——至少对我而言如此。更希望人们别总执着于“单一语言解决所有问题”的思维定式。在Java开发环境中,用Java编写命令行工具和脚本或许更合理。但这并不意味着从长远来看它是最有效的工具链。
使用模块和jlink技术,你的Java映像完全可以小于200MB。带完整UI的桌面应用甚至能压缩到30MB。
你对C# AOT技术的漠视令我困惑。其生成的二进制文件可与Go或Rust媲美,Linux平台的Hello World程序仅需1.1MB。
问题在于打包后的Java命令行工具同样需要20MB+空间。对于这类程序而言,最小体积依然过大。此外,上次尝试AoT编译时简直痛苦不堪——这对始终以模块化动态设计为核心的生态系统而言是巨大变革。我热爱Java,但在命令行应用领域,只要可能我都会选择Rust。
但编译耗时极长。至少几年前我使用.NET9时的体验如此。
在WSL/Fedora 43环境下构建Hello World:
“`
> time dotnet publish
恢复完成 (0.4s)
dn-hw net10.0 linux-x64 成功 (2.4s) → bin/Release/net10.0/linux-x64/publish/
构建成功耗时 3.1s
实际耗时 0m3.571s
用户时间 0m2.784s
系统时间 0m0.673s
> time go build main.go
实际耗时 0m3.309s
用户时间 0m8.864s
系统时间 0m1.741s
“`
显然我不知道这在非简单应用中会如何表现。
你确定是开发者吗?因为你似乎在混淆语言技术概念?
这艘船早就开走了。
我们的Go命令行工具动辄上百MB,常打包进GB级别的容器里。没人会在意,至少没人认真要求我们精简代码。
我的固态硬盘想和你聊聊 🙂 我并非主张每个应用都必须控制在千字节级别。但终端应用占用数兆空间确实奇怪。不过当应用采用静态链接且需要OpenSSL等组件时,我就能理解这种情况了。
以实际应用为例,Java开发的命令行工具kcctl(Kafka Connect客户端)就是典范:[https://github.com/kcctl/kcctl/](https://github.com/kcctl/kcctl/)。该工具采用原生二进制(通过GraalVM实现),启动仅需几毫秒,因此可在Tab补全过程中即时调用,并能与Kafka Connect REST API进行往返通信而毫无延迟。
安装通过brew完成,与您使用的其他命令行工具体验一致。二进制文件体积较大(52 MB),但实际使用中影响甚微。GraalVM的构建时间仍不理想(虽有改善)。交叉编译是另一痛点,我通过平台专属的GitHub Action运行器进行管理。从用户角度看这些都不重要——我敢打赌多数用户根本不知道kcctl是用Java编写的。
Babashka自2019年发布以来持续获得用户青睐。我部署了大量Babashka shebang脚本,启动速度极快。虽然我绝不愿使用Java语法,但基于JVM的Clojure库支持AOT编译且可动态加载。通过Graal构建。[https://babashka.org](https://babashka.org)
babashka内置了卓越的命名空间。亮点包括:babashka.fs——对Java文件系统类实现功能化高效封装;babashka.process——提供与shell进程交互、I/O及管道处理的实用函数。我认为babashka的封装极简,比Python脚本更便捷。无需庞大虚拟环境,仅需在本地安装小于70MB的二进制文件。Borkdude FTW。
没错——这正是我们需要的——不仅限于Clojure领域。
我已完成[https://github.com/jbangdev/jbang-jash](https://github.com/jbangdev/jbang-jash)用于Shell进程管理,smallrye的进程I/O也为优质Shell API贡献良多。
文件访问可能是另一个方向。
jbang提供类似二进制工具——目前基于bash+jvm架构,但安装极其简便。我手头的原生jbang二进制文件甚至不足70MB 🙂
绝对要深入研究babashka获取灵感。
我从很久以前就开始为终端编写Java实用工具,主要是因为对Java极其熟悉。除非加载海量类库(比如包罗万象的应用或Clojure),否则它从未真正慢过。现在Clojure有Babashka:快得惊人。
而GraalVM编译的Java更是迅捷无比。
回溯到2005年,二十年前的老电脑上,Java从命令行启动确实明显迟缓。但在当今的计算机上?
如今我开发的终端应用涵盖Clojure(Babashka)、Bash和Java(最近因需要某个.jar文件,又没有现成的Clojure封装,懒得重写,索性直接用Java编写了命令行工具)。
或许,或许,或许在树莓派上运行我的Java命令行应用时,我确实能感受到启动时间。具体是树莓派2和3(因为我没有更新的型号)。
启动时间本身不是问题。但选择其他语言编写命令行应用可能另有考量。
作为这类应用的重度用户,这篇文章的论点对我毫无说服力。
与其在数字生态中给Java或埃里森更多空间,我宁愿用柠檬汁浸泡的冰锥自残。此处谈埃里森绝非政治立场,纯粹因其糟糕透顶。
页面上有人评论甲骨文。为何仍有人纠结于甲骨文或埃里森?若说他们对Java有何贡献,反倒是助其蓬勃发展。
真正的威胁始终是…谷歌。他们复制了微软的手段(微软因此遭反垄断处罚),而谷歌却逍遥法外。谷歌终结了Eclipse作为Android开发IDE的地位,将这块业务转交给俄罗斯伙伴JetBrains。
威胁Java的正是谷歌,而非甲骨文。
我秉持进步理念——正如我不会因马斯克是个纳粹小丑就亏本抛售环保的特斯拉,更不会因某个亿万富翁混蛋把斯蒂芬·科尔伯特赶下《今夜秀》就放弃我的GraalVM编译的babashka二进制文件。我完全可以哀叹并斥责两者任性愚蠢,却不必像圣托马斯·莫尔那样殉道流血。
当工具链变得过于臃肿时,编程语言就会流失用户。
你必须学习(并持续掌握)构建工具、单元测试框架、前端/后端开发工具、分发打包系统、满足这些需求的目录结构等等,简直令人厌烦。
随后又出现某种新颖闪亮的工具,所需配套工具却少得多。轻松构建软件的诱惑令用户难以抗拒。
这永无止境。
问题不仅在于语言本身,更在于思维定式与文化氛围。当Java中 *System.exit()* 甚至 *System.println()* 都被视为代码异味,而我必须主动争取才能让异常处理脱离公司统一规范时,我宁可直接用Rust写完算了。
这正是我博客的核心观点——我们需要转变思维方式。
其他生态系统施加的“企业规则”少得多——挣脱束缚吧 🙂
全公司范围的规范若泛泛限制而非结合具体情境,本身就是不良设计。
很久没关注GraalVM了。这次获取了x86_64架构的graalvm-jdk-25.0.1+8.1版本。虽然比Julia快得多,且43毫秒在“人类感知层面”不算慢,但相较其他竞品仍显迟缓。这是基于helloworld.jar的测试[1]。在我的笔记本电脑(i7-1370P,P核)上使用tim[2]测试:
“`
$ tim “awk ‘{}’/n’
97.5 ± 1.5 μs (已扣除)静态开销
94.9 ± 3.2 μs awk ‘{}’/n
“`
此外,可能存在某种调优方法,但当前使用了超过128 MiB的RSS。
[1]: [https://github.com/jarirajari/helloworld](https://github.com/jarirajari/helloworld) [2]: [https://github.com/c-blake/bu/blob/main/doc/tim.md](https://github.com/c-blake/bu/blob/main/doc/tim.md)
这只是一个普通的JVM,若启用Graal组件则为可选配置,但当前未使用。默认内存分配基于可用内存的百分比及未提交内存(即可供其他程序使用的内存)。人们提及Graal时,通常指无需安装JVM即可运行的AOT编译可执行文件。有时人们也会将Graal JIT作为替代C1/C2的方案提及,该方案同样支持虚拟机模式。您当前使用的是纯HotSpot虚拟机服务器模式,因桌面场景优先级降低(如JWS停用),其优化的客户端模式已被移除。
您说得对,我为造成误解致歉。
`native-image -jar helloworld.jar helloworld` 编译耗时竟达17秒,这可能是最小规模的项目。这确实令人担忧在启动开销敏感的场景中追求性能优化的迭代过程,但生成的可执行文件运行速度显著提升——仅比`tcc -run`慢约1.8倍:
“`
97.0 +- 1.7 μs (已扣除)开销
98.2 +- 2.8 μs awk ‘{}’/n
“`
Perl 需要额外链接两个共享库,但运行速度却更快。因此性能仍有优化空间,感谢您的指正。
(另附四组较快程序的对比数据,以佐证误差条的可信度。实际上,在分时操作系统环境下,分布曲线的尾部比高斯分布更重,因此单个正负符号不足以体现差异。)
—
编辑:ld.so/动态链接开销一直困扰着我。我花了些时间搭建musl+zlib构建环境,最终获得完全静态链接的二进制可执行文件后得到如下结果:
“`
398.2 ± 4.2 μs ./helloworld-sta>/n
“`
(需说明:/n -> /dev/null 是我在所有系统中设置的便捷符号链接。测试环境为 Linux 6.18.2 及与前次相同的 CPU。)
此外,静态链接版本的RSS仅约4.2 MiB,而dash和awk组合约为1.8 MiB。因此占用空间扩大2.4倍,但运行时间仅增加约4倍——这看似批评,但它们通常是效率冠军。二进制文件体积相当庞大(内存占用约为原来的2倍):
“`
$ size *sta
text data bss dec hex filename
2856644 3486552 3184 6346380 60d68c helloworld-sta
“`
因此我认为,在2026年,Java启动开销已相当可接受。希望这些“真实数据”能为讨论增添些许精准度。所谓“区区几毫秒”对我而言远不如400±4微秒具体,或许还有人持相同看法。
感谢您修正后的评估。仅供您知悉,HotSpot团队正在Leyden项目[1]下开发一系列AOT/JIT评估选项。当前评估环境仍需在完全开放模式(JIT)与封闭模式(AOT)之间二选一。混合模式将提供可调参数,例如通过AOT预热同时保留动态类加载功能,并保持应用程序的快速编译时间。这将消除硬性限制,使开发者能根据应用部署/使用场景选择最适配的约束条件。
[1] [https://openjdk.org/projects/leyden](https://openjdk.org/projects/leyden)
> 试试GraalVM原生映像。毫秒级完成。
尝试构建GraalVM原生映像。耗时数分钟。
我同意构建可能多花些时间,但对小型命令行工具而言绝对不算多。将 jbang 转为原生仅增加 1-2 分钟,且全程在 GitHub 动作运行器中完成,实际操作中这不会影响终端用户,因此我认为不成问题。
比你机器容量还多的内存也会消失殆尽。
所幸这仅发生在AOT编译阶段,运行时不会如此。
没错,但本文灵感源于将Java作为终端风格编程语言使用,因此AOT步骤属于关键路径环节。
“清理笔记”的LLM未能察觉这点,倒也不足为奇。
Java 21已支持此功能,创建如下简短Java文件即可立即运行:
“`
class HelloWorld {
public static void main(String[] args) {
System.out.println(“Hello, World!”);
}
}
java HelloWorld.java
“`
注意保留.java扩展名,这是直接运行文件。
运行时间 java HelloWorld.java
“`
Hello, World!
real 0m0.278s
user 0m0.613s
sys 0m0.066s
“`
现在你可以做得更好:
“`
#!/usr/bin/env java –source 25
void main() {
IO.println(“Hello, World!”);
}
“`
[https://openjdk.org/jeps/330](https://openjdk.org/jeps/330) [https://openjdk.org/jeps/458](https://openjdk.org/jeps/458) [https://openjdk.org/jeps/512](https://openjdk.org/jeps/512)
当需要获取第三方依赖时,我常将这些方法与[https://get-coursier.io/](https://get-coursier.io/)结合使用。
2026年会不会是锤子在背面加个十字槽的年份?毕竟你总会碰到那种奇怪的带肋钉子。
终端里的Java早已运行得精妙绝伦,它叫Babashka。Clojure很酷,Bash够用,而Java提供了坚如磐石的基础。
听起来像俄语,恕不奉陪。
摘自 [https://old.reddit.com/r/java/comments/1pzfmka/2026_the_year…](https://old.reddit.com/r/java/comments/1pzfmka/2026_the_year_of_java_in_the_terminal/)
[https://www.jbang.dev/](https://www.jbang.dev/)
同意,Java至今仍支持纯单文件执行模式。Java foo.java。我经常用它替代脚本。这是种兼具稳定性与灵活性的语言,甲骨文近年做得不错。新版Java框架相当易用且轻量。我们生产环境中原生部署了Lambda函数,运行良好。
这如何处理类路径?
想象一下:运行程序竟需要先知道它用什么语言编写的。
$ python foobar
不行。
$ gcc foobar
不行。
$ g++ foobar
哎呀,别这样。
$ go foobar
该死。
$ rust foobar
$ c# foobar
这程序到底用什么写的??!!
$ node foobar
简直浪费时间。
$ java foobar
胡扯!
$ ocaml foobar
拜托,编程语言没那么多吧!
$ tcl foobar
终于成功了!
所以才要用 jreleaser 打包发布啊,这样直接运行 `foobar` 就行
别把开发流程和终端用户流程混为一谈…这可不是 Java 独有的问题。
我对 Java 开发最大的不满在于 LSP/DAP 支持的现状。试过在 VS Code 写 Java,支持依然非常不完善。最渴望的两项功能是:(1) 自动下载依赖项源代码;(2) 断点触发时暂停所有线程([https://github.com/microsoft/vscode-java-debug/issues/722](https://github.com/microsoft/vscode-java-debug/issues/722))。
目前尚未发现任何编辑器或IDE能接近IntelliJ的体验。若要在终端中编写Java,我们或许还需思考如何在终端内实现Java编程——或者这两者是否完全无关?
嗯——在vscode里源代码自动下载功能明明能正常工作啊?
若不使用Maven自动下载,需在配置中添加“java.maven.downloadSources”: true。
暂停所有线程确实是个合理的遗漏。感觉该有人去贡献这个功能——有人愿意接手吗?
关于你的问题——我确实怀念在终端里轻松编辑Java代码的体验。我用nvim starter pack来实现,但这里缺少优秀的jbang支持的LSP来真正流畅地操作…这也列入我的2026愿望清单啦 🙂
我之前不知道JBang,看起来很棒。它的工作原理和uv类似吗?
我几乎找不到任何理由在本地运行Java编写的命令行工具,尤其当它需要安装JVM时。这完全没有必要。
Pkl算是例外,它至少使用Graal Native Image构建,但(我认为)若用其他语言实现,其普及度仍会更高。
话虽如此,若Java社区有意将合理工具移植到其平台,我相信Claude能出色地完成BubbleTea及其相关工具的初始化工作。
假设无需安装JVM(我同意不应如此),你为何在意CLI工具的编程语言?我的意思是,你真的知道某个二进制文件是用Go、Rust还是其他语言实现的吗?从用户角度看,这根本没什么实质区别。
> Pkl至少是用Graal Native Image构建的,但(我认为)如果用其他语言编写,它_依然_会获得更广泛的采用。
你认为原因何在?
这会影响程序体积、参数处理方式等诸多方面。
至于Pkl为何采用Java:它最初是为配置Java应用而开发,且深度依赖Truffle框架。Pkl是开源时的命名,此前在苹果内部使用的是另一个名称,因此选择Java的理由更为明确。
> 话虽如此,若Java社区有意将合理工具移植到其平台,我相信Claude能出色地完成BubbleTea及其相关工具的初始化工作。
楼上有位网友似乎已实现你描述的功能:[https://github.com/WilliamAGH/tui4j](https://github.com/WilliamAGH/tui4j)
恕我直言,这纯属胡说八道——包括某些评论在内。Java爱好者堪称粉饰Java及JVM缺陷的世界冠军。
用Go编写命令行应用是这样的:下载Go后,你立即拥有管理依赖、编写应用并通过简单命令编译成轻量级可分发二进制文件所需的所有工具。
现在看看Java的流程: 首先,你需要下载A(!)个JDK——而且有多个版本。许多新手被各种JDK搞得晕头转向,但暂且不提这个。JDK本身无法处理依赖关系;你很可能最终要使用Maven或Gradle,这两者都复杂又麻烦,需要你处理XML(Maven)或Groovy/Kotlin。被忽视的是像JBang这类工具的潜力,这类工具本应开箱即用。Scala团队通过scala-cli有效解决了这个问题,它现在已成为默认的Scala运行器。无论如何,你离完成还很远。你刚刚弄清楚如何编写应用程序,现在需要弄清楚如何分发它们。这涉及理解jpackage——若想获得小于100MB的应用程序,很可能需要预先使用jlink处理。更糟的是,若应用程序使用Java 9+模块,你将不得不应对模块化本身的复杂性。即便成功克服所有障碍,最终生成的应用程序仍会包含捆绑的JRE。一个经过压缩、模块化的“Hello World”应用程序,体积至少30MB,启动耗时数百毫秒。
Graal Native技术允许预编译应用程序为原生可执行二进制文件。但预编译Java应用程序会因运行时类初始化、反射等机制变得复杂,因此Graal编译器需要大量前期配置。虽然有追踪代理工具辅助配置编译,但即便借助这些工具,过程依然极其繁琐且不可靠。此外,生成的二进制文件体积庞大,且与upx压缩工具兼容性差。
我认为JDK开发者可借鉴Scala CLI的经验——该工具现已成为Scala的默认运行环境。若Java能开箱即用类似方案,必将极大提升开发体验。
*恕我直言,这纯属胡扯——包括某些评论在内。Java爱好者堪称粉饰Java及JVM缺陷的世界冠军。*
我也爱你。
*用Go语言编写命令行应用程序就是这样的:你下载Go后,立即拥有所有必需工具,只需简单命令就能管理依赖项、编写应用程序,并将它们编译成轻量级可分发的二进制文件。*
检查 – 同意。
*现在,让我们看看Java中的实现过程….<吐槽>*
感觉你错过了过去五年的技术进步…让我展示使用 jbang 时 Java 的实现方式:
你下载 JBang 后,立即拥有所有必要工具:管理依赖项、编写应用程序,并通过简单命令运行其他 Java 应用程序。
既然你可能不相信我,我在此展示部分操作:
`jbang init -t cli hello.java` – 生成声明picocli依赖的hello.java文件,可直接运行`./hello.java`,甚至能执行`jbang app install hello.java`后仅用`hello`调用。此功能同样适用于自定义脚本、现有jar包或Maven工件。
– 它还会自动为你下载正确的JDK;你可轻松切换版本,只需执行`jbang –java 25 hello.java`,甚至`jbang –java 8 hello.java`(如果你真想穿越时光 :))。Java版本可直接嵌入脚本或jar文件,因此终端用户无需关注版本问题。
`jbang edit hello.java` 将提供基于vscodium的IDE安装选项,为您创建Java编写环境。
`jbang export fatjar hello.java` 可生成可运行胖jar文件
`jbang export maven|gradle hello.java` 提供完整的Maven/Gradle支持,满足企业合规需求 🙂
您甚至可通过将源代码提交至GitHub仓库,仅需执行`jbang <仓库URL>`或使用jbang目录等功能即可运行和分发这些源代码。应用场景丰富多样。
阅读本文及Reddit讨论后,我注意到最终发布jar/可执行文件的过程仍过于繁琐。鉴于jbang/jreleaser与现代JDK已具备所有必要组件(个人观点),我将尝试解决这一难题。
*此外还有Graal Native技术,可将应用程序预编译为原生可执行二进制文件。* *但预编译Java应用时需处理运行时类初始化、反射等复杂问题,因此Graal编译器需要大量前期配置。虽然有追踪代理工具辅助配置编译,但即便如此仍极其耗时且可靠性不足。此外,生成的二进制文件体积庞大且与upx兼容性差。*
兼容性差——具体表现?虽然存在常规upx开销,但实际使用时似乎“正常工作”?
关于GraalVM Native——绝非完美或易用;但Quarkus确实构建了完整的Java库与框架生态,在原生构建场景下能无缝运行。
话虽如此——我认为多数使用场景并不需要完全转向原生。
*我认为JDK开发者可以借鉴Scala CLI(现为Scala默认运行器)。若Java能开箱即用类似工具,必将大有裨益。*
没错,我等不及JDK开发者行动,所以亲手打造了jbang来实现这个功能。
你基本忽略了我所有观点,反而提出权宜之计——这恰恰是多数人想避免的。谁还在用胖JAR分发应用?这是什么年代?2004年吗?应用理应以可执行文件形式分发。我曾多次提出关于jpackage和jlink的诸多问题,而jbang完全未解决这些问题。更可笑的是,你竟指责我过去五年未使用Java——这简直荒谬至极!我在JVM平台开发软件已有近二十年。讽刺的是,正因jlink和jpackage使用体验糟糕,我不得不自己编写sbt插件。
关于UpX:它根本无法处理Graal生成的Windows二进制文件——详见此问题报告:[https://github.com/oracle/graal/issues/7605](https://github.com/oracle/graal/issues/7605)。开发者三年间始终置之不理。而它对Go二进制文件或.NET的AOT编译器却完美兼容。我并非要贬低你的项目,但现实是:没有多少Java经验的人根本不会去发现并安装jbang。这类功能本该作为Java的开箱即用特性。
*你基本无视了我所有观点,反而提出权宜之计——这恰恰是多数人想避免的。谁还在用胖JAR分发应用?这是2004年吗?应用理应以可执行文件形式发布。*
而npm、Python等生态系统至今仍不这么做。它们实质上分发的是带有依赖元数据的jar文件。
我从未主张使用胖jar(尽管这同样可行)。
为何Java世界不能像其他生态系统那样接受这种方案?
我知道过去为何没人这么做——毕竟那时还没有 jbang 这类工具,就像 npm(以及快速的 Node 运行时)出现前,JavaScript 也没有实现过类似功能…
*我曾多次提出关于 jpackage 和 jlink 的诸多问题,但 jbang 从未解决过任何一个。*
我明确写道:“阅读本文及reddit讨论后,我认为最终发布jar/可执行文件的过程依然过于繁琐。鉴于jbang/jreleaser和现代JDK已具备所有必要组件(个人观点),我将尝试解决这一难题。”因此我从未宣称jbang已解决问题——我只是指出其改进空间。
我实际展示(或至少尝试说明)的是:你抱怨scala-cli这类工具时,提到Go语言能开箱即用实现所有功能…而jbang的存在正是为了弥合这种差距。
*此外,你指责我过去五年未使用Java,这实在荒谬;*
我从未如此宣称。我只是指出你似乎忽略了近年的技术进步(jbang正是解决你所列多数问题的关键方案)。
*我在JVM平台开发软件近二十年。讽刺的是,由于jlink和jpackage使用体验糟糕,我不得不自己编写sbt插件。*
是的,jlink和jpackage确实不够完善。
我尚未尝试解决这个问题,因为我通常使用jreleaser来规避这些痛点——我也承认问题尚未彻底解决…但同时想说明的是,将所有内容都作为原生操作系统二进制文件分发并非绝对必要,其他生态系统也并非如此操作。
天啊,就连Go语言都允许通过本地编译来运行Git仓库…jbang同样支持类似的工作流——而且是在纯Java之上实现的。
*关于UpX:它根本无法处理Graal生成的Windows二进制文件——详见此问题报告:[https://github.com/oracle/graal/issues/7605](https://github.com/oracle/graal/issues/7605)。开发者三年间始终置之不理。而它对Go二进制文件或.NET的AOT编译器却完美兼容。*
明白了——我好久没在Windows上试过了,看起来GraalVM 21版本还能用,问题只出现在后续版本。
*我并非要贬低你的项目,但现实是:没有Java经验的人根本不会主动发现并安装jbang。这类功能本该作为Java的默认特性提供。*
是啊——但Node、Python等语言最初也没提供这些功能。
要求默认工具链包含这些功能才能被视为实用,这正是典型的Java思维。
真好奇为何还有人坚持使用Maven/Gradle/sbt——它们同样不随Java本身提供呢 🙂
Java就像当代的COBOL,而JVM如同IBM 360架构。
但延迟问题。我25年来用过的Java应用,没有一个能在合理时间内启动。
> 启动时间合理
这恐怕是带着确认偏误的草率概括?
“`
$ time keenwrite.bin –version
KeenWrite 版本 3.6.5
版权所有 2016-2025 白魔法软件有限公司
用户时间 0m0.329s
“`
克劳德补充:
> 值得注意的是,这确实是人们对Java的普遍认知,且存在历史依据(尤其2000年代的Swing桌面应用)。但“没有Java应用…永远不会”这种绝对论断是谬误——这是将有限个人经验过度泛化为普适结论。
这并非泛化。我作为具体个体陈述自身经历。我完全不清楚你的应用是什么,也毫无理由使用它。
使用GraalVM原生二进制文件时这根本不是问题。参考示例[https://news.ycombinator.com/item?id=46445989](https://news.ycombinator.com/item?id=46445989):该命令行工具以毫秒级启动,快到能在标签补全时调用,执行REST API时毫无延迟感。
即便在JVM环境下运行,近几年的性能也已大幅提升,例如得益于AOT类加载与链接技术。以单节点Kafka代理为例,其启动时间约为300毫秒。
时间对比具有(或应当具有)相对性。[https://news.ycombinator.com/item?id=46447490](https://news.ycombinator.com/item?id=46447490)
GraalVM的开销确实比静态链接的Dash脚本高出500倍。
终端界面或许不受影响,但文章同时提及了图形界面和命令行工具。许多用户通过shell使用命令行工具。当执行`for file in *.c; do tool “$file”; done`(仅举简单示例)时,即使数十毫秒级的纯开销也会变得明显。这绝非理论推测。我最近在使用python3时就遇到过这个问题,但又不愿将所有f字符串重写为python2格式。可见这确实是实际应用中的痛点(至少对部分用户而言如此)。
那jshell呢?它随每个Java发行版附带
为 jshelled(适用于 Gradle 项目的 jshell)打个无耻广告 [https://github.com/gravitation1/jshelled](https://github.com/gravitation1/jshelled)
是啊,我也以为这会是关于 jshell 的讨论。
jshell 太棒了,我觉得知道它的人还不够多!
2026年将成为学习语言之年——当你审阅LLM生成的代码时
我理解这篇文章提出的可行性论点。
但无法认同其合理性论点。方枘圆凿虽可行,未必是明智之举。
我绝不会强迫不喜欢Java的人接受它——但我想说的是,Java这个楔子其实比多数人想象的更圆润。所以别因为别人说必须用,就贸然改用Python、Go、JavaScript这类稍圆的替代品 🙂
核心争议或许在于它已不再是方枘。
文章元评论:行动胜于空谈。
缺乏实例演示 → 操作门槛过高 → 懒得查证,反正已有Python/Go/Ruby的快速命令行方案。用LLM生成的方案更省事。
博主在此——这篇刚发完我就开吃新年晚餐了——新年快乐 🙂
希望文章能更深入探讨实际使用jBang和jReleaser时的工作流具体形态。
这正是我2026年计划深化探索的方向,期待获得同行助力——否则我只能困在自己的回音壁里 🙂
奇怪的是完全没提到Groovy——我记得它最初的动机不正是这类使用场景吗?
老实说
看到终端里居然没有Java简直震惊
虽然我自己不用,但这也太离谱了。
说真的,他们能在没有Java支持的情况下取得如此成就令人钦佩,但关键在于Java开发者更倾向于在IDE中完成所有操作——因此我认为在IDE中集成Java代理比切换工作模式更能带来回报
现有Java代理系统和IDE集成已相当完善——但仅凭这些无法打破固有认知。
真正的障碍不在于能力,而在于认知:许多人甚至没尝试过终端Java就放弃了。与此同时,尽管Python/JS存在类似(甚至更糟)的启动成本、依赖蔓延和多GB安装包等问题,其终端工具却呈现爆发式增长——人们对此的反应往往是“这样就行,先发布再完善”。
除非Java在终端环境中成为常态,否则IDE中的代理功能也无法改变这种思维定式。
明显是AI生成的内容。终端里的Java听起来糟透了。编写Java代码本身就糟透了。
恕不奉陪。
你上次编写Java代码是什么时候?它已与Java 8时代大不相同。
虽然我已离开这个生态圈,但它确实做对了许多事。
我赞同Nick的观点。我最后一次专业编写Java是在2024年末,当时使用了所有最新最强大的框架(显然并非我所愿)和工具链(公平地说,Java生态的工具链确实无与伦比)。
在主要使用Go、Rust和Erlang(兼顾TypeScript、C#、Python、Swift、C、C++等语言)十余年后,这次经历成为我最终离开那家雇主的决定性因素。
你能证明这篇帖子是由AI撰写的吗?
我不确定能否断言这绝对是AI所作(毕竟大型语言模型往往因训练数据影响而形成特定写作风格),但文中确实存在大量可疑句式,暗示可能出自AI之手:
– “听着,我要说的话可能听起来很疯狂…”
– 但关键在于:没有任何因素能阻止我们……
– 长破折号。我认为单凭破折号本身并不能证明是AI所作——就像它也不能证明作者受过良好教育——但结合其他特征或许可以。
– 问答式句式结构。
– “这不是X,而是Y”的句式模式。
以上特征均出现在文章开头部分。
我同意。文末“前进之路”和“核心结论”的分析部分也让我产生同样印象。
我认为这是人类与大型语言模型混合创作的产物
Max在/r/java帖子中承认自己撰写了原文,但使用AI进行了润色。
不,终端上运行Java(坦白说任何基于JVM的语言)都是糟糕的体验。
我并非主张淘汰Java。但在我看来,Java几乎在每个层面都是失败的实验,至少不该为它开辟新应用场景。
所以不行。天啊千万别,终端里绝不能有Java。
更多吐槽见此:[https://blog.habets.se/2022/08/Java-a-fractal-of-bad-experim…](https://blog.habets.se/2022/08/Java-a-fractal-of-bad-experiments.html)
然而Java远不止于Java本身。JVM上存在着众多更现代的语言。其生态系统庞大且仍具有强大惯性。
没错。我的部分批评针对语言本身,部分则指向JVM——因此具有跨语言意义。
例如Kotlin确实没那么糟糕。但正如我所描述的,JVM始终是个失败的实验。
但愿不会如此。
我会改用这个:[https://babashka.org/](https://babashka.org/)
babashka是为Clojure设计的
Clojure本质是Java。你拥有完整生态系统的访问权限,却无需承受任何头疼问题。
我也是来表达同样观点的
一旦引入JVM,人们就会逃之夭夭。
Graal编译器必不可少,而生成的二进制文件会变得臃肿不堪。
谢绝。Go语言简单得多,Rust体积更小。Java可以去办公室储物柜里自生自灭了。
Go语言“更简单”?当真?
C语言更简单,Python更简单,但Go?
确实如此
[https://leapcell.io/blog/the-origins-and-design-philosophy-o…](https://leapcell.io/blog/the-origins-and-design-philosophy-of-go-language)
Go最初的设计初衷是为谷歌员工简化工作,让软件工程变得轻松。2025年的今天,我可以证明Go确实简单易用。但能否用Go实现目标则是另一回事。不过Go确实拥有基础结构和流畅流程,复杂性往往源于对Go哲学的理解不足。
Go堪称最简洁的语言之一。虽非总能轻松构建大规模系统,但其纯粹性毋庸置疑。
确实——Go比Java更简洁,它既不纵容(生态系统也无法容忍)企业级Java常见的架构滥用,本身也难以滋生此类弊端。
句末的问号让我们能轻松援引贝特里奇定律。
是啊——我既没提出事实性主张又质疑它。我问的是“谁赞同我?”,而“不”或“是”都不是有意义的回答 🙂
“binarymax懂是非题的概念吗?”
请用Rust或Go
单二进制文件,无复杂依赖,超赞
Go?
那年是2003,我困在空调失灵的闷热地下城里,苦思冥想黑魔法蚂蚁战术的正确法术组合。几年后我写了海量XML,先是为原生J2EE,后来为Spring框架。我们抱怨,我们困惑,没人理会——直到某天我们决定“去他妈的,管他Ruby慢如蜜糖,我只想摆脱痛苦!”
若2026年的我听到“Java构建”就暴走,还请原谅。
我们许多人与Java有着漫长的关系,这种关系充满毒性与虐待。我们离开了。如今Java宣称自己已改变,已成熟。或许是真的,甚至很可能是真的,但另一方面,现在你的毒性前任发现了他父亲的身分——而他的名字叫拉里·埃里森。
难道我该永远不用Go语言,只因找不到好用的调试器?该抱怨Python是单线程?该嫌弃JavaScript是无类型的混乱?该排斥只运行在Windows上的C#?
我很高兴地说,我认为所有语言都有其优缺点,它们都在不断进化,我们都不该固守陈旧的偏见。没错,Java确实被这些偏见所束缚,但我主张别让诸如你这样的偏见阻碍我们追求进步与革新。
Java是陈旧技术…当你开始接触Python、Go、Rust、TypeScript、Swift…还需Java吗?
“陈旧”的含义似乎与你暗示的不同。建议在任何AI中输入以下提示与之辩论:“请用编程语言的标准定义’陈旧’。”
期待实现AbstractCommandlineParserFactoryBeanServicePatternFactory
这说明你确实使用了Java的特定小众领域,不过我明白你说的有趣之处。
当初我展示用`myapp`命名类并通过 jbang myapp.java 运行时,大家反应都很奇怪。
Java本身没有技术限制;只是陈旧的坏习惯束缚了人们的思维而已 😉
> AbstractCommandlineParserFactoryBeanServicePatternFactory
…Locator