codePoints() 是处理 Unicode 补充字符(如 Emoji、中文、数学符号)的正确方式,因为它返回完整码点(int),能正确识别代理对;而 charAt() 和 for-each char 仅操作 16 位 char,会将辅助平面字符(U+10000 以上)错误拆分为两个代理字符,导致乱码或逻辑错误。

Java 中用 codePoints() 遍历字符串,是处理 Emoji、中文、数学符号等 Unicode 补充字符(Supplementary Characters)的正确方式,因为它能正确识别代理对(surrogate pairs),避免把一个 Emoji 拆成两个乱码字符。
为什么 charAt() 和 for-each char 会出错
Java 的 char 是 16 位无符号整数,只能表示基本多文种平面(BMP)内的字符(U+0000–U+FFFF)。而很多 Emoji(如 ?、??、?)和部分罕见汉字位于辅助平面(U+10000 及以上),在 UTF-16 编码中需要用两个 char(即高代理 + 低代理)表示。直接用 charAt(i) 或 for (char c : str.toCharArray()) 会把一个 Emoji 当作两个独立的代理字符处理,导致显示异常、长度误判或逻辑错误。
用 codePoints() 获取真正的 Unicode 码点
String.codePoints() 返回的是 IntStream,每个元素是一个完整的 Unicode 码点(int 类型,范围 U+0000–U+10FFFF),天然支持所有 Unicode 字符,包括 Emoji。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 遍历示例:
String text = "Hello???";
text.codePoints().forEach(cp -> {
System.out.printf("U+%04X → %s%n", cp, Character.toString(cp));
}); - 转换为数组更便于索引操作:
int[] cps = text.codePoints().toArray();
for (int i = 0; i String ch = String.valueOf(Character.toChars(cps[i]));
// ch 就是完整的单个字符(含 Emoji)
}
安全获取第 n 个“字符”(码点)
如果需要按视觉位置访问(比如取第 3 个 Emoji),不能用 charAt(2),而应先将字符串转为码点数组再索引:
立即学习“Java免费学习笔记(深入)”;
- int[] cps = "A??B".codePoints().toArray();
int thirdCodePoint = cps[2]; // → 'B' 的码点,不是代理高位 - 注意:
String.length()返回的是char数量(可能含代理对),不是真实字符数;cps.length才是实际 Unicode 字符个数。
与 StringBuilder / StringBuffer 配合时保持一致性
若需构建或修改含 Emoji 的字符串,也应使用基于码点的操作:
- 追加码点:
StringBuilder sb = new StringBuilder();
sb.appendCodePoint(0x1F9D1); // ?
sb.appendCodePoint(0x200D); // ZWJ
sb.appendCodePoint(0x1F4BB); // ?
// 得到 ?? - 替换/删除某位置字符:
int[] cps = original.codePoints().toArray();
// 修改 cps 数组后
String result = new String(codePointsToChars(cps));
(可用Character.toChars(int)将每个码点转为 char 数组,再拼接)

















