В чем различие между методами String codePoints() и chars()?

Писал скрипт по пересчету символов в строке при помощи Stream API и столкнулся со следующей ситуацией.
В классе String обнаружил два, по сути, идентичных метода, возвращающих IntStream:

  • chars()
  • codePoints()

Оба возвращают стрим ASCII кодов символов. Вот здесь вопрос и заключается, в чем их различия? Когда, где и в какой ситуации использовать конкретный метод? И еще вопрос на засыпку. Как получить чистый стрим символов не прибегая к приведению к char вот так:

str.codePoints().mapToObj(c -> (char) c)

Или так:

str.chars().mapToObj(c -> (char) c)

Результат в обоих вариациях идентичен.

Заранее Всем спасибо за ответы.


Ответы (1 шт):

Автор решения: default locale

Некоторые символы в Юникод кодируются двумя 16-битными словами, так называемыми «суррогатными парами».

Для таких символов codePoints вернет одно число (кодовую точку) соответствующее паре слов, а chars два числа по одному для каждого значения char (16-битное слово).

Например, для эмодзи:

String s = "?";
System.out.println(s.chars().count());      //2
System.out.println(s.codePoints().count()); //1

Различие между методами достаточно хорошо выделяется документации:

chars
Returns a stream of int zero-extending the char values from this sequence. Any char which maps to a surrogate code point is passed through uninterpreted.

codePoints
Returns a stream of code point values from this sequence. Any surrogate pairs encountered in the sequence are combined as if by Character.toCodePoint and the result is passed to the stream. Any other code units, including ordinary BMP characters, unpaired surrogates, and undefined code units, are zero-extended to int values which are then passed to the stream.

chars
Возвращает поток дополненных нулями значений char из этой последовательности. Каждое значение char, соответствующее суррогатам, передается без интерпретации.

codePoints
Возвращает поток значений кодовых точек из этой последовательности. Суррогатные пары, встречающиеся в последовательности объединяются так же как и в Character.toCodePoint и результат передается в поток. Любые другие кодовые точки, включая символы из основной многоязычной плоскости, непарные суррогаты, и неопределенные кодовые точки, дополняются нулями до значений int, которые затем передаются в поток.

Соответственно, chars всегда будет возвращать значения меньше 65536, в отличие от codePoints.

Также можете почитать:

→ Ссылка