Java: create a string from a Latin-1 byte array

Viewed 539

I have a byte[] array containing Latin-1 encoded characters, and I want to create a Java String from it.

I know I can do new String(bytes), but looking at the implementation code, it involves convoluted logic: looking up the name of the default encoding, allocating a decoder, passing the byte array to the decoder. So I suspect that (at least for short strings) the following is faster:

    char[] expanded = new char[bytes.length];
    for (int i=0; i<bytes.length; i++) {
        expanded[i] = (char)(bytes[i] & 0xff);
    }
    return new String(expanded);

But that's not particularly efficient either: the String(char[]) constructor makes a copy of my newly minted char[] array, just in case I have the temerity to modify it later.

Any comments on either of these approaches? Is there a better way? (Note: most of the strings will be short. And I know I could microbenchmark this, and I know that if I did, there would be a high risk of getting wrong answers...)`

3 Answers

Have you tried this?

String str = new String(byteArray, StandardCharsets.ISO_8859_1);

If you are targeting modern versions of Java, use the String(byte[], Charset) constructor. It has been heavily optimized, and will avoid creating encoder objects and temporary buffers for the most common use cases.

new String(bytes, StandardCharsets.ISO_8859_1);

If you are targeting a wide range of Java versions including Java 8 and earlier, use the deprecated String(byte[],int) constructor:

new String(bytes, 0)

This use case is the only reason why why this constructor still exists and can never be removed. It's the fastest and lowest overhead way to create a string from ASCII or iso8859-1 bytes.

See also the comments in the related bug report https://bugs.openjdk.java.net/browse/JDK-6405064

It is true that when creating small strings containing only ASCII or Latin-1 characters, the deprecated constructor is the most efficient way. A number of developers have discovered this fact, and so there is a critical dependence on these constructors to continue working. There is a a good case for denigrating, rather than deprecating, these constructors. We could do more work on making Charset lookup and String construction more efficient, thereby removing the need for developers to use the hibyte constructor performance hack.

Note that Americans/Western Europeans already enjoy many advantages, like getting front-row seats in the BMP.

As a practical matter, these constructors will never be removed. Too many people would scream.

Since java-9 there is a non-public constructor, that will directly set the value and the coder, but it is not public. You could get to it, but of course it could break un-expectedly.

    byte[] b = new byte[]{'a'};
    byte coder = 0; // latin_1

    Constructor<String> cons = String.class.getDeclaredConstructor(byte[].class, byte.class);
    cons.setAccessible(true);
    String result = cons.newInstance(b, coder);

    System.out.println(result);
Related