**I just announced the new *** Learn Spring * course, focused on the fundamentals of Spring 5 and Spring Boot 2:

*Learn Spring*course, focused on the fundamentals of Spring 5 and Spring Boot 2:

**>> CHECK OUT THE COURSE**

Last modified: September 15, 2019

In this tutorial, we'll take a look at different ways to convert a byte array to a hexadecimal *String,* and vice versa.

We'll also understand the conversion mechanism and write our implementation to achieve this.

First of all, let's take a look at the conversion logic between byte and hexadecimal numbers.

The bytes are 8 bit signed integers in Java. Therefore, we need to **convert each 4-bit segment to hex separately and concatenate them**. Consequently, we'll get two hexadecimal characters after conversion.

For instance, we can write 45 as 0010 1101 in binary, and the hexadecimal equivalent will be “2d”:

0010 = 2 (base 10) = 2 (base 16) 1101 = 13 (base 10) = d (base 16) Therefore: 45 = 0010 1101 = 0x2d

Let's implement this simple logic in Java:

public String byteToHex(byte num) { char[] hexDigits = new char[2]; hexDigits[0] = Character.forDigit((num >> 4) & 0xF, 16); hexDigits[1] = Character.forDigit((num & 0xF), 16); return new String(hexDigits); }

Now, let's understand the above code by analyzing each operation. First of all, we created a char array of length 2 to store the output:

char[] hexDigits = new char[2];

Next, we isolated higher order bits by right shifting 4 bits. And then, we applied a mask to isolate lower order 4 bits. Masking is required because negative numbers are internally represented as two's complement of the positive number:

hexDigits[0] = Character.forDigit((num >> 4) & 0xF, 16);

Then we convert the remaining 4 bits to hexadecimal:

hexDigits[1] = Character.forDigit((num & 0xF), 16);

Finally, we create a *String* object from the char array. And then, returned this object as converted hexadecimal array.

Now, let us understand how this will work for a negative byte -4:

hexDigits[0]: 1111 1100 >> 4 = 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 & 0xF = 0000 0000 0000 0000 0000 0000 0000 1111 = 0xf hexDigits[1]: 1111 1100 & 0xF = 0000 1100 = 0xc Therefore: -4 (base 10) = 1111 1100 (base 2) = fc (base 16)

It's also worth noting that the *Character.*forDigit*()* method always returns lowercase characters.

Now, let's convert a hexadecimal digit to byte. As we know, a byte contains 8 bits. Therefore, **we need two hexadecimal digits to create one byte**.

First of all, we'll convert each hexadecimal digit into binary equivalent separately.

And then, we need to concatenate the two four bit-segments to get the byte equivalent:

Hexadecimal: 2d 2 = 0010 (base 2) d = 1101 (base 2) Therefore: 2d = 0010 1101 (base 2) = 45

Now, let's write the operation in Java:

public byte hexToByte(String hexString) { int firstDigit = toDigit(hexString.charAt(0)); int secondDigit = toDigit(hexString.charAt(1)); return (byte) ((firstDigit << 4) + secondDigit); } private int toDigit(char hexChar) { int digit = Character.digit(hexChar, 16); if(digit == -1) { throw new IllegalArgumentException( "Invalid Hexadecimal Character: "+ hexChar); } return digit; }

Let's understand this, one operation at a time.

First of all, we converted hexadecimal characters into integers:

int firstDigit = toDigit(hexString.charAt(0)); int secondDigit = toDigit(hexString.charAt(1));

Then we left shifted most significant digit by 4 bits. Consequently, the binary representation has zeros at four least significant bits.

Then, we added the least significant digit to it:

return (byte) ((firstDigit << 4) + secondDigit);

Now, let's examine the *toDigit()* method closely. We are using the *Character.digit()* method for conversion. **If the character value passed to this method is not a valid digit in the specified radix, -1 is returned.**

We're validating the return value and throwing an exception if an invalid value was passed.

At this point, we know how to convert a byte to the hexadecimal, and vice versa. Let's scale this algorithm and convert byte array to/from hexadecimal *String*.

We need to loop through the array and generate hexadecimal pair for each byte:

public String encodeHexString(byte[] byteArray) { StringBuffer hexStringBuffer = new StringBuffer(); for (int i = 0; i < byteArray.length; i++) { hexStringBuffer.append(byteToHex(byteArray[i])); } return hexStringBuffer.toString(); }

As we already know, the output will always be in lowercase.

First of all, we need to check if the length of the hexadecimal *String* is an even number. This is because a hexadecimal *String* with odd length will result in incorrect byte representation.

Now, we'll iterate through the array and convert each hexadecimal pair to a byte:

public byte[] decodeHexString(String hexString) { if (hexString.length() % 2 == 1) { throw new IllegalArgumentException( "Invalid hexadecimal String supplied."); } byte[] bytes = new byte[hexString.length() / 2]; for (int i = 0; i < hexString.length(); i += 2) { bytes[i / 2] = hexToByte(hexString.substring(i, i + 2)); } return bytes; }

We can **create an object of type BigInteger by passing a signum and byte array**.

Now, we can generate the hexadecimal *String* with the help of static method format defined in *String* class:

public String encodeUsingBigIntegerStringFormat(byte[] bytes) { BigInteger bigInteger = new BigInteger(1, bytes); return String.format( "%0" + (bytes.length << 1) + "x", bigInteger); }

The format provided will generate a zero-padded lowercase hexadecimal *String.* We can also generate an uppercase string by replacing “x” with “X”.

Alternatively, we could've used the *toString()* method from *BigInteger*. The subtle **difference of using the toString() method is that the output isn't padded with leading zeros**:

public String encodeUsingBigIntegerToString(byte[] bytes) { BigInteger bigInteger = new BigInteger(1, bytes); return bigInteger.toString(16); }

Now, let's take a look at hexadecimal *String* to *byte* Array conversion:

public byte[] decodeUsingBigInteger(String hexString) { byte[] byteArray = new BigInteger(hexString, 16) .toByteArray(); if (byteArray[0] == 0) { byte[] output = new byte[byteArray.length - 1]; System.arraycopy( byteArray, 1, output, 0, output.length); return output; } return byteArray; }

**The toByteArray() method produces an additional sign bit**. We have written specific code for handling this additional bit.

Hence, we should be aware of these details before using the *BigInteger* class for the conversion.

The *DataTypeConverter* class is supplied with JAXB library. This is part of the standard library until Java 8. Starting from Java 9, we need to add *java.xml.bind* module to the runtime explicitly.

Let's take a look at implementation using the *DataTypeConverter* class:

public String encodeUsingDataTypeConverter(byte[] bytes) { return DatatypeConverter.printHexBinary(bytes); } public byte[] decodeUsingDataTypeConverter(String hexString) { return DatatypeConverter.parseHexBinary(hexString); }

As displayed above, it is very convenient to use *DataTypeConverter* class. The **output of the printHexBinary() method is always in uppercase**. This class supplies a set of print and parse methods for data type conversion.

Before choosing this approach, we need to make sure the class will be available at runtime.

We can use the *Hex* class supplied with the Apache commons-codec library:

public String encodeUsingApacheCommons(byte[] bytes) throws DecoderException { return Hex.encodeHexString(bytes); } public byte[] decodeUsingApacheCommons(String hexString) throws DecoderException { return Hex.decodeHex(hexString); }

The **output of encodeHexString is always in lowercase**.

Let's take a look at how *BaseEncoding* class can be used for encoding and decoding byte array to the hexadecimal *String:*

public String encodeUsingGuava(byte[] bytes) { return BaseEncoding.base16().encode(bytes); } public byte[] decodeUsingGuava(String hexString) { return BaseEncoding.base16() .decode(hexString.toUpperCase()); }

**The BaseEncoding encodes and decodes using uppercase characters by default**. If we need to use lowercase characters, a new encoding instance should be created using static method lowercase.

In this article, we learned the conversion algorithm between byte array to hexadecimal *String*. We also discussed various methods to encode byte array to hex string and vice versa.

It isn't advised to add a library to use a couple of utility methods only. Therefore, if we aren't using the external libraries already, we should use the algorithm discussed. The *DataTypeConverter* class is another way to encode/decode between various data types.

Finally, the complete source code of this tutorial is available on GitHub.