“真正能让程序员开心的,从来不是什么 “革命性重构”,而是某天突然发现,以前天天写的几十行重复代码,现在一行都不用敲了。”
2022年3月,JDK 18正式发布。它不是LTS,生命周期只有半年,它没带来什么颠覆性的大招,却精准地戳中了我们这些开发者日常的痛点,而且这几个小改动,真的能让我每天少皱好几次眉头!
最痛的那个痛点,肯定是跨平台文本乱码——这个我后面单独说。哦对了,还有个超实用的:现在敲一行命令就能起个临时HTTP服务器,再也不用去翻Python的http.server参数,或者临时装Node.js的包了。最后还有个预览版的大杀器雏形:switch终于能玩模式匹配了!
说白了,JDK 18就是想让我们今天的编码,比昨天少敲点没用的、少踩点莫名其妙的坑。
📌 JDK 18 官方特性总览 JDK 18的所有新特性都是基于 JSR 393(《Java SE 18 发布规范》) 来实现的——不过我没去翻那几十页的PDF,反正好用就行。 大概梳理了下,它的改动主要是这三类(或者说这三类我用得最多/最期待):
switch的模式匹配终于出第二预览版了,这可是Java模式匹配拼图里的重要一块!每一项改动,都透着一股“务实”的劲儿,不求惊天动地,但求让你少皱一次眉头。
我敢说,这绝对是JDK 18最香的特性,没有之一!
说个真实的踩坑经历:去年年底,我帮朋友维护一个Windows上跑了快10年的小工具,加了个导出Excel的功能,本地Windows 10上跑,中文全对。一传到他公司的CentOS 7服务器上,导出的Excel里中文全是乱码,连文件名都不对。查了整整两个小时,才发现是因为工具里用了new String(bytes)和FileWriter,没指定字符集——Windows默认是GBK,CentOS默认是UTF-8。
为了这事,我那天晚上把工具里所有没指定字符集的IO和文本处理API,全补了StandardCharsets.UTF_8,补了大概有五六十处,手都酸了。
结果JDK 18直接把这个问题给解决了!现在,几乎所有常用的IO和文本处理API,默认字符集都是UTF-8,不管你在Windows、Linux还是macOS上跑。
我后来又把那个工具的JDK版本升到了18,把补的那五六十处字符集参数全删了——重新打包,传到Windows 10和CentOS 7上跑,结果完全一致!那一刻我差点跳起来,终于不用再跟运维解释为什么要加-Dfile.encoding=UTF-8这个启动参数了。
当然,也不是完全没有风险。除非你是维护那种十几年前的、专门在Windows上跑的、完全依赖GBK的老系统,否则升级时基本不会有问题。如果真的遇到了,官方也留了条后路:加-Dfile.encoding=COMPAT就能回退到旧的平台默认字符集。
这看似是一个很小的改动,却真的终结了困扰我们Java开发者二十多年的跨平台文本编码之痛。以后,“字符集”这个词,终于可以更多地用在业务逻辑里,而不是基础IO操作的补丁里了。
这个功能真的救了我好几次急!
以前想在本地快速起个HTTP服务,要么得写几行Python——我之前还因为同事的电脑上Python版本是2.7,python -m http.server报错,折腾了半天换成python3 -m http.server;要么就得去临时装Node.js的http-server包,有时候网络不好,装半天装不上。
现在,JDK 18自带了!只需要在终端敲一行命令:
jwebserver一个监听8000端口的静态文件服务器就跑起来了,当前目录下的所有文件(除了隐藏文件和符号链接)都能通过浏览器访问。
上周给同事展示一个HTML性能报告那次,真的太方便了:直接在他的MacBook上cd到报告的解压目录,敲了jwebserver,然后把http://localhost:8000/report.html发给他,他点开就能看,整个过程不到10秒,连IDE都不用开。
当然,它确实很“简单”:不支持HTTPS,不能执行CGI或者Servlet,就是个纯静态文件服务器。但反正我遇到的所有临时分享场景——比如给同事看个HTML、测试个CSS/JS、快速传个小文件(虽然传文件不如scp,但胜在不用开终端权限)——它都能搞定。
这又是一个典型的“开发者体验”优化。它把一个我们经常会遇到的、低复杂度但有时候挺麻烦的需求,变成了一个零成本的操作。这种小改动,真的最能体现一个平台对我们开发者的用心。
switch 的模式匹配(第二预览版,JEP 420)等了好久!switch 终于出第二预览版的模式匹配了!虽然还是预览版,短期内肯定用不到生产环境,但已经能看出它的潜力了。
先澄清个小细节哈:JDK 18的第二预览版还不能配合记录模式(Record Patterns),那个是JDK 19才有的。不过没关系,光是现在的守卫模式和更完善的类型检查,就已经让我兴奋不已了。
以前,处理一个密封类的不同子类型,虽然可以用switch,但有时候还是得写额外的if-else来做条件判断:
// JDK 17 的写法
String result = switch (expr) {
case ConstantExpr c -> {
if (c.value() > 100) yield "Large constant: " + c.value();
else yield "Small constant: " + c.value();
}
case AddExpr a -> a.lhs() + " + " + a.rhs();
// ...
};在JDK 18里,加了--enable-preview就能这么写:
// JDK 18 第二预览版的写法
String result = switch (expr) {
case ConstantExpr c && c.value() > 100 -> "Large constant: " + c.value();
case ConstantExpr c -> "Small constant: " + c.value();
case AddExpr a -> a.lhs() + " + " + a.rhs();
// ...
};我上周加了--enable-preview,把一个用了十几年的、处理表达式树的老工具里的部分代码重写了——以前要写好几层if-else的,现在一行case就搞定了,代码可读性直接提升了好几个档次!
我知道它现在只是预览版,语法可能还会变,而且生产环境肯定不会随便开--enable-preview。但看到switch这个用了十几年的控制流语句,正在变得越来越灵活、越来越简洁,我就觉得Java的未来还是很有希望的。
switch的模式匹配,是继instanceof模式匹配之后,Java向更简洁、更安全的编程方式迈出的又一步。它让复杂的类型检查和数据提取逻辑,变得清晰了很多。
switch模式匹配的预览,让我们得以一瞥Java语言将如何变得更加优雅和强大。@snippet标签就行,还能自动测试示例代码的正确性——这对我们这些写技术博客或者维护开源项目文档的人来说,真的省了不少事。finalize()方法,终于被官方标记为“准备移除”了。以后做资源清理,还是老老实实用try-with-resources吧!总结一下,JDK 18就是一次很务实的小更新。它没有搞什么大动作,就是解决了几个我们日常经常遇到的小问题:跨平台的字符集混乱、繁琐的临时服务器搭建。同时,它也给我们打开了一扇小窗户,让我们看到了Java语言的未来方向——switch的模式匹配预览,虽然还不完善,但已经很让人期待了。
虽然JDK 18不会在生产服务器上长期驻留,但它带来的便利,我已经在本地开发环境里完全感受到了。以后,我肯定会在本地开发环境里继续用它,直到下一个LTS的到来。
📢 延伸阅读建议
[1] JSR 393: Java SE 18 规范: https://www.jcp.org/en/jsr/detail?id=393
[2] OpenJDK JDK 18 官方页面: https://openjdk.org/projects/jdk/18/
[3] JEP 400: UTF-8 by Default: https://openjdk.org/jeps/400
[4] JEP 408: Simple Web Server: https://openjdk.org/jeps/408
[5] JEP 420: Pattern Matching for switch (Second Preview): https://openjdk.org/jeps/420