Java >> Java Program >  >> Tag >> char

Skriva 2 tecken till en enda Java-tecken

Här är ett annat trevligt trick som vi använde när vi skapade Chronicle FIX-Engine med ultralåg latens.

När det gäller att läsa data från en ström av byte är det mycket effektivare, om möjligt, att lagra data i en char istället för att behöva läsa den till en String . (Du undviker åtminstone att skapa ett String-objekt, även om detta kan mildras genom att använda en cache eller arbeta med CharSequence istället för String men det är ämnet för ett annat inlägg.)

Med JMH-riktmärken har jag hittat dessa tidpunkter:(Jag har inte inkluderat källkoden för detta eftersom detta kommer att bli föremål för ett annat inlägg där jag beskriver de olika metodologierna mer detaljerat).

Läsning av 2 ascii-tecken från en byte strömmar in i:

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

Poängen är att det tar minst 3 gånger längre tid att läsa data till en String än en char , och det tar inte ens hänsyn till det skräp som skapas.

Så det säger sig självt att när du vet att du förväntar dig data som alltid är ett enda tecken, snarare än att läsa in dessa data till en String variabel bör du läsa in den i en char .

Tänk nu om du vet att den data du förväntar dig på strömmen inte är mer än 2 tecken. (Du hittar den här situationen, till exempel i FIX 5.0 tag 35 msgType). Måste du använda en sträng så att du kan få plats med den extra karaktären? Vid första tankar verkar det så, trots allt kan en röding bara innehålla ett enda tecken.

Eller kan det?

En java char består av 2 byte inte en. Om du därför vet att din data består av ascii-tecken vet du att endast en enda byte (av de 2 byten i char ) kommer att användas. Till exempel är 'A' 65 dock till 'z' som är 122.

Du kan skriva ut värdena som passar in i en enda byte med denna enkla loop:

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

Du är nu fri att använda rödingens andra bye för att hålla det andra ascii-tecknet.

Så här gör du:

I det här exemplet har du läst 2 byte 'a' och 'b' och vill lagra dem i ett enda tecken.

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)); 

För att bättre förstå detta låt oss titta på binären:

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

Sammanfattning

Det är mer effektivt att läsa data till en char snarare än en sträng. Om du vet att du har högst 2 ascii-tecken kan de kombineras till ett enda Java-tecken. Använd naturligtvis bara denna teknik om du verkligen är orolig för ultralåg latens!

Java-tagg