文章摘要(AI生成)
JDK 9 引入了多项改进,最显著的是将.properties文件的默认编码从ISO-8859-1改为UTF-8。这一变动解决了以往在处理中文等多字节字符时出现的乱码问题,开发者无需再使用native2ascii工具进行字符转义,直接书写汉字即可。同时,ASCII字符在两种编码下保持兼容,确保老旧文件的正常使用。除了编码调整,JDK 9还推出了五个重要的增强提案(JEP),包括新的版本号方案(使版本信息更清晰)、平台日志API(简化日志管理)、增强的废弃机制(提供废弃元素的详细信息),以及对Project Coin的语法改进(提升代码简洁性)。这些新特性为开发者在现代多语言环境中的编码处理和项目管理提供了更大的便利。
❓文件解析的问题
给你一个简单的 .properties
文件:
a=测试
我们想当然地用 Java 自带的 Properties
类来加载它:
public static void main(String[] args) {
Properties properties = new Properties();
try (FileInputStream input = new FileInputStream("test.properties")) {
properties.load(input);
String a = properties.getProperty("a");
System.out.println("value: " + a);
} catch (IOException e) {
e.printStackTrace();
}
}
但运行后你会看到输出是乱码:
value: æµè¯
这并非 Bug,而是 Java 的历史遗留设计 —— properties
文件默认使用 ISO-8859-1(Latin-1)编码。ISO-8859-1 是单字节编码,仅能表示西欧语言字符,无法直接处理中、日、韩等多字节字符集的字符。与之对比,现代操作系统几乎都默认采用 UTF-8 编码,它是一种变长编码,能涵盖世界上几乎所有字符,是目前互联网上使用最广泛的字符编码方案。正因如此,在读取中文、日文、韩文等字符时会出现乱码问题,尤其是 macOS 用户对此感受更为明显。由于 Java 早期设计时采用了 ISO-8859-1 作为.properties文件的默认编码,在现代多语言环境下就出现了兼容性问题。
🧠 系统默认编码到底是啥?
现代系统的默认编码基本是 UTF-8:
-
Linux(Ubuntu、Debian、Fedora 等):默认en_US.UTF-8。在 Linux 系统中,UTF-8 编码的广泛使用使得系统能够更好地支持全球范围内的语言和字符。对于开发者而言,编写涉及字符处理的程序时,若遵循 UTF-8 编码规范,能更方便地与系统交互。
-
macOS:自 10.9 Mavericks 起终端默认 UTF-8。这使得开发者在处理文本相关操作时,无需再额外进行编码转换。
-
Windows:虽曾使用本地编码(如 GBK),但 Win10/11 可开启 UTF-8 模式。Windows 系统过去长期使用本地编码,如 GBK,主要是为了兼容中文环境下的软件和文档。但随着全球化的推进,从 Win10/11 开始可开启 UTF-8 模式,这为开发者在进行跨平台开发和处理多语言内容时提供了便利。
✅ JDK 9 之后,Java 改了!
从JDK 9 开始(JEP 226),Java 官方将ResourceBundle
加载的.properties
文件默认编码改成了UTF-8。
这一改变带来诸多便利:
-
不再需要native2ascii工具转义中文。 在 JDK 8 及之前,由于.properties文件默认采用 ISO-8859-1 编码,对于非 ISO-8859-1 编码范围内的字符,如中文,就需要使用native2ascii工具将其转义为
\uXXXX
的形式,这增加了开发的复杂性。而在 JDK 9 及之后,由于默认编码变为 UTF-8,开发者可以直接在.properties文件中书写中文。 -
直接写中文、阿拉伯文等都能被正确读取。 因为在 JDK 9 及之后,.properties文件默认编码变为 UTF-8,所以可以直接书写各种字符,并且 Java 能够正确读取。
-
不影响老文件:ASCII 范围在 ISO-8859-1 与 UTF-8 编码中兼容。 ASCII 字符在两种编码中表示形式一致,所以对于老文件中原本使用 ASCII 字符的部分,不会产生兼容性问题。
🔍 对比一下前后差异:
项目 | JDK 8 及之前 | JDK 9 及之后(JEP 226) |
---|---|---|
.properties 默认编码 |
ISO-8859-1(Latin-1) | ✅ UTF-8 |
中文处理 | 必须转义成 \uXXXX |
✅ 直接写中文 |
工具依赖 | 需借助 native2ascii |
✅ 不再需要 |
加载方式 | Properties.load() |
✅ 同样方法,行为改进 |
🚀 除此之外,JDK 9 还改了这些(精选 5 个重要 JEP)
除了属性文件编码的重大优化,JDK 9 还带来了很多实用改进。以下是 5 个值得关注的增强提案(JEP):
🆕 JEP 223:新的版本号方案
版本号格式从1.8.0_202
变为9.0.1
/ 11
/ 17.0.8
,统一使用$MAJOR.$MINOR.$SECURITY.$PATCH
格式。
其中MAJOR
表示主版本号,通常用于重大功能更新;MINOR表示次版本号,用于添加新功能;SECURITY表示安全补丁版本号;PATCH表示普通补丁版本号。这种新格式使版本信息更清晰,更好地支持版本管理、自动升级以及 LTS 标识。在进行自动升级时,系统能更准确地根据版本号判断是否需要升级以及升级的影响范围;对于 LTS 版本,通过版本号可以更明确地标识其长期支持的特性
🧾 JEP 264:平台日志 API
新增System.getLogger()
作为统一日志入口。
在 JDK 9 之前,Java 中不同的日志框架各自为政,开发者在项目中使用日志功能时需要在不同的日志框架之间进行选择和适配,导致代码中日志相关的依赖较为复杂。而现在,无论项目使用java.util.logging
还是第三方的 Log4j 等日志框架,都可通过该统一入口操作,实现了模块间低耦合的日志调用方式,非常适合现代化架构,各个模块在记录日志时更加独立,不会因为日志框架的变化而对其他模块产生较大影响。
⚠️ JEP 277:增强的废弃机制
@Deprecated
注解支持since
和forRemoval
属性。
在 JDK 9 之前,@Deprecated注解仅表明某个方法、类或字段已过时,不推荐使用,但未提供何时废弃及是否即将删除的详细信息。JEP 277 增强后的废弃机制,通过**since
属性可明确指出元素从哪个版本开始被废弃,forRemoval
属性**可表明是否计划在未来某个版本中删除该元素。如此一来,开发者使用代码时能更清楚哪些代码即将被淘汰,便于提前进行代码迁移,同时编译器也能依据这些属性给出更智能的警告信息。
🧪 JEP 213:Project Coin 小幅升级
在语法方面有诸多改进:
-
匿名类可使用
diamond<>
。在匿名类中使用diamond<>
语法,使得代码在创建匿名类实例时更加简洁。例如,在 JDK 9 之前创建一个匿名的ArrayList
实例可能需要完整地写出泛型类型,而在 JDK 9 之后可以使用<>
简化代码。 -
私有方法可使用
@SafeVarargs
。对于私有方法使用@SafeVarargs
注解,主要用于确保可变参数的使用安全性,避免在运行时可能出现的堆污染等问题。 -
try-with-resources 可重用变量。该特性使在使用try-with-resources语句时,能在不同的资源声明中重用相同的变量名,进一步简化了代码结构,提升了代码的可读性和编写效率,让语法更优雅,减少冗余,编写代码更高效。
📌 总结对比:JDK 8 vs JDK 9
功能方向 | JDK 8 | JDK 9 改进(对应 JEP) |
---|---|---|
版本号方案 | 1.8.0_xx |
新格式 9.0.1 (JEP 223) |
属性文件编码 | ISO-8859-1 | 默认 UTF-8(JEP 226) |
日志支持 | 无统一日志接口 | 平台日志 API(JEP 264) |
废弃机制 | 简单 @Deprecated 注解 |
支持版本与移除标记(JEP 277) |
语法糖 | 初版 Project Coin | 更多便捷写法(JEP 213) |
💬 最后
如果你还在用 JDK 8,别忘了属性文件中的中文要转义;如果你升级到了 JDK 9+,可以直接开开心心写 UTF-8 的 .properties
文件了,再也不用背 \u4F60\u597D
!
评论区