Статьи

Запись 2 символов в один символ Java

Вот еще одна приятная уловка, которую мы использовали при создании FIX-Engine с очень низкой задержкой.

Когда речь идет о считывании данных из потока байтов, гораздо эффективнее, если это возможно, хранить данные в char а не считывать их в String . (По крайней мере вы избегаете создания объекта String, хотя это может быть смягчено с помощью кэша или работы с CharSequence а не со String но это тема другого поста.)

Используя тесты JMH, я нашел следующие моменты: (я не включил исходный код для этого, поскольку это будет темой другого поста, где я опишу различные методологии более подробно).

Считывание 2 символов ascii из потока байтов в:

1
2
3
4
String - 34.48ns
Pooled String - 28.57ns
StringBuilder - 21.27ns
char (using 2 chars method) - 6.75ns

Дело в том, что для чтения данных в String требуется как минимум в 3 раза больше времени, чем для char , и это даже не учитывает созданный мусор.

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

А что если вы знаете, что ожидаемые данные в потоке не более 2 символов? (Вы найдете эту ситуацию, например, в теге FIX 5.0 35 msgType ). Нужно ли вам использовать строку, чтобы вы могли разместить дополнительный символ? На первый взгляд кажется, что символ может содержать только один символ.

Или это может?

Символ java состоит из 2 байтов, а не одного. Поэтому, если вы знаете, что ваши данные состоят из символов ascii, вы знаете, что будет использоваться только один байт (из 2 байтов в char ). Например, «A» равно 65, хотя «z» равно 122.

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

1
2
3
4
for (int i = 0; i < 256; i++) {
    char c = (char)i;
    System.out.println(i+ ":" + c);
}

Теперь вы можете свободно использовать другой свиток символа для удержания второго символа ascii.

Это способ сделать это:

В этом примере вы прочитали 2 байта ‘a’ и ‘b’ и хотите сохранить их в одном символе.

1
2
3
4
5
6
7
byte a = (byte)'a';
byte b = (byte)'b';
//Now place a and b into a single char
char ab = (char)((a << 8) + b);
 
//To retrieve the bytes individually see code below
System.out.println((char)(ab>>8) +""+ (char)(ab & 0xff));

Чтобы лучше понять это, давайте посмотрим на двоичный файл:

01
02
03
04
05
06
07
08
09
10
11
12
13
byte a  = (byte)'a' // 01100001
 
byte b  = (byte)'b' // 01100010
 
As you can see below, when viewed as a char, the top 8 bits are not being used
 
char ca = 'a' // 00000000 01100001
 
char cb = 'b' // 00000000 01100010
 
Combine the characters with a taking the top 8 bits and b the bottom 8 bits.
 
char ab = (char)((a << 8) + b); // 01100001 01100010

Резюме

Это более эффективное чтение данных в символ, а не в строку. Если вы знаете, что у вас есть максимум 2 символа ascii, они могут быть объединены в один символ Java. Конечно, используйте эту технику, только если вы действительно беспокоитесь о сверхнизкой задержке!

Ссылка: Запись двух символов в один символ Java от нашего партнера по JCG Дэниела Шайя в блоге Rational Java