假设我要从String中删除所有非字母。

String s = "abc-de3-2fg";

我可以使用IntStream来做到这一点:
s.stream().filter(ch -> Character.isLetter(ch)).  // But then what?

为了将该流转换回String实例,我该怎么办?

另一方面,为什么我不能将String视为Character类型的对象流?
String s = "abc-de3-2fg";

// Yields a Stream of char[], therefore doesn't compile
Stream<Character> stream = Stream.of(s.toCharArray());

// Yields a stream with one member - s, which is a String object. Doesn't compile
Stream<Character> stream = Stream.of(s);

根据javadoc,Stream的创建签名如下:



我能想到的唯一(糟糕)方法是:
String s = "abc-de3-2fg";
Stream<Character> stream = Stream.of(s.charAt(0), s.charAt(1), s.charAt(2), ...)

当然,这还不够好……我想念的是什么?

最佳答案

这是问题第二部分的答案。如果您有一个通过调用IntStream生成的string.chars(),则可以通过转换为Stream<Character>然后通过调用char将结果装箱来获得mapToObj。例如,以下是将String转换为Set<Character>的方法:

Set<Character> set = string.chars()
    .mapToObj(ch -> (char)ch)
    .collect(Collectors.toSet());

请注意,强制转换为char对于将装箱结果为Character而不是Integer是必不可少的。

现在,处理charCharacter数据的最大问题是,补充字符被表示为char值的替代对,因此任何处理单个char值的算法都可能在出现补充字符时失败。

(补充字符似乎是我们不需要担心的晦涩的Unicode功能,但是据我所知,所有表情符号都是补充字符。)

考虑以下示例:
string.chars()
      .filter(Character::isAlphabetic)
      ...

如果提供包含代码点U + 1D400(数学粗体A)的字符串,则将失败,而将失败。该代码点在字符串中表示为代理对,而代理对的值都不是字母字符。为了获得正确的结果,您需要这样做:
string.codePoints()
      .filter(Character::isAlphabetic)
      ...

我建议始终使用codePoints()

现在,给定一个IntStream的代码点,如何将其重新组装为String? Sleiman Jneidi's answer使用collect()的三参数IntStream方法是合理的(+1)。

这是一个替代方案:
StringBuilder sb = ... ;
string.codePoints()
      .filter(...)
      .forEachOrdered(sb::appendCodePoint);
return sb.toString();

如果您已经有一个用来存储字符串数据的StringBuilder,这可能会更灵活一些。您不必每次都创建一个新的StringBuilder,也不必随后将其转换为String

07-27 13:23
查看更多