java 的 chars() 流如何与 reduce 一起工作?它使用字符编码吗?

How does java's chars() stream work with reduce? Does it use character encoding?

代码大战的挑战是计算在 Long 的单个整数变成单个数字之前必须将其相互相乘多少次。例如

39 -> 3 * 9 = 27 -> 2 * 7 = 14 -> 1 * 4 = 4 // 答案是 3

这是已发布的解决方案之一 -

class Persist {
  public static int persistence(long n) {
    int times = 0;
    while (n >= 10) {
      n = Long.toString(n).chars().reduce(1, (r, i) -> r * (i - '0'));
      times++;
    }
    return times;
  }
}

我对代码的“(i - '0')”部分感到很困惑。我昨天才知道 Java 的 chars() 方法 returns 一个代表字符的 IntStream,所以立即使用 reduce 对我来说很有意义。但随后它减去了一个让我失望的字符,因为它似乎适用于它正在处理字符,但是它们是如何相乘的?

我复制了上面的代码,然后删除了字符减法,所以这是一个我理解的简单 reduce 语句,又名

n = Long.toString(n).chars().reduce(1, (r, i) -> r * i);

然后是 运行 调试器。第一个循环将 3 * 9 计算为 2907。这个答案从何而来?我最好的猜测是它与字符编码有关,但为什么减去 char '0' 会修复它?

A char 只是 0 to 0xFFFF 范围内的数字,在打印或连接到字符串时具有特殊含义。

你可以轻松写

int i = 'A';

还有

char c = 65;

两个变量指的是同一个数字,因此,

System.out.println(i == c);

会打印 true 但是当你执行

System.out.println(i);
System.out.println(c);

不同的变量类型将导致选择具有不同值解释的不同方法。

您可以使用 char 值进行计算,并始终将它们分配给 int 变量,因为它们的值范围适合 int 值范围,因此可以处理序列char 个值和 IntStream 并保存另一个专用流 class 的创建。您只需要关心正确解释结果值。

说到编码,char被定义为一个UTF-16单元,所以如果你想给它起个名字,那就对了。

对于你的问题的例子,知道字符 '0''9' 在 UTF-16 编码中有相邻的值是至关重要的(它适用于所有 Unicode 编码),所以不是只有从 '0' 中减去 '0' 才能得到 int0,从 '0' 中的任何字符减去 '0''9' 范围会给你相应的 int 值。 '0' 的编码值是 48 这一事实甚至与此逻辑无关。

注意 codepoints() method which returns a sequence of Unicode code point values in the range 0 to 1,114,111 (0x10FFFF). For characters in the BMP 的存在,这些值与 char 值相同,但 BMP 之外的值被编码为两个 UTF-16 单元,因此更容易处理它们codepoints() 流。