Question

Convert Byte Arrays to Hex Strings in Java

csharparrayshex

Question

How can you convert a byte array to a hexadecimal string and then convert a hexadecimal string back into a byte array in Java?

Short Answer

By the end of this page, you will understand how hexadecimal encoding works, how to convert byte[] to a hex string, how to parse a hex string back into bytes, and what common mistakes to avoid when working with binary data in Java.

Concept

Hexadecimal is a base-16 number system that represents binary data in a human-readable form. Each hexadecimal character represents 4 bits, so one byte, which has 8 bits, is represented by exactly 2 hex characters.

In Java, a byte[] stores raw binary data. This is useful for files, hashes, encryption keys, network packets, and image data. But raw bytes are not easy for humans to read or print. That is where hex strings help.

For example, this byte array:

byte[] data = { 15, 42 };

can be represented as:

0f2a

This matters in real programming because many systems display binary values as hex:

  • MD5, SHA-256, and other hash outputs
  • Token and key debugging
  • File signatures
  • Network protocol inspection
  • Logging raw binary values safely

The reverse conversion is also common. If a program receives a hex string such as ff0a10, it may need to turn it back into real bytes for further processing.

A key rule to remember is:

  • 1 byte = 2 hex characters

So any valid hex string for conversion back to bytes must have an even number of characters.

Mental Model

Think of a byte array as a box of raw machine values, and a hex string as a label printed in a format humans can read.

  • The byte[] is the real data.
  • The hex string is a readable representation of that data.

It is similar to writing a street address on paper instead of describing a location using map coordinates in binary.

Another simple way to think about it:

  • A byte is one full item.
  • Hex splits that item into two visible symbols.
  • So every byte becomes two hex digits.

If you see the hex string 4f, that is one byte. If you see 4f2a, that is two bytes.

Take Quiz

Syntax and Examples

Convert byte[] to hex string

A common approach is to loop through each byte and format it as two hexadecimal characters.

public static String bytesToHex(byte[] bytes) {
    StringBuilder hex = new StringBuilder();
    for (byte b : bytes) {
        hex.append(String.format("%02x", b));
    }
    return hex.toString();
}

Example

byte[] data = { 10, 15, 31 };
String hex = bytesToHex(data);
System.out.println(hex);

Output:

0a0f1f

%02x means:

  • %x = format as hexadecimal
  • 2 = use at least 2 characters
  • 0 = pad with leading zero if needed

Convert hex string to byte[]

To convert back, read the string two characters at a time, parse each pair as a base-16 number, and store it as a byte.

public static byte[] hexToBytes(String hex) {
    if (hex.length() % 2 != 0) {
        throw new IllegalArgumentException("Hex string must have an even length");
    }

    byte[] bytes = new byte[hex.length() / 2];
    for (int i = 0; i < hex.length(); i += 2) {
        String hexPair = hex.substring(i, i + 2);
        bytes[i / 2] = (byte) Integer.parseInt(hexPair, 16);
    }
    return bytes;
}

Example

String hex = "0a0f1f";
byte[] data = hexToBytes(hex);

for (byte b : data) {
    System.out.println(b);
}

Output:

10
15
31

Full example

public class HexExample {
    public static String bytesToHex(byte[] bytes) {
        StringBuilder hex = new StringBuilder();
        for (byte b : bytes) {
            hex.append(String.format("%02x", b));
        }
        return hex.toString();
    }

    public static byte[] hexToBytes(String hex) {
        if (hex.length() % 2 != 0) {
            throw new IllegalArgumentException("Hex string must have an even length");
        }

        byte[] bytes = new byte[hex.length() / 2];
        for (int i = 0; i < hex.length(); i += 2) {
            String hexPair = hex.substring(i, i + 2);
            bytes[i / 2] = (byte) Integer.parseInt(hexPair, 16);
        }
        return bytes;
    }

    public static void main(String[] args) {
        byte[] original = { 72, 101, 120 };

        String hex = bytesToHex(original);
        System.out.println("Hex: " + hex);

        byte[] restored = hexToBytes(hex);
        System.out.print("Bytes: ");
        for (byte b : restored) {
            System.out.print(b + " ");
        }
    }
}

This converts bytes to hex, then converts the hex back to the original bytes.

Step by Step Execution

Consider this code:

byte[] data = { 10, 15 };
String hex = bytesToHex(data);

Using this method:

public static String bytesToHex(byte[] bytes) {
    StringBuilder hex = new StringBuilder();
    for (byte b : bytes) {
        hex.append(String.format("%02x", b));
    }
    return hex.toString();
}

Step by step

  1. data contains two bytes: 10 and 15
  2. A new empty StringBuilder is created
  3. The loop reads the first byte: 10
  4. String.format("%02x", 10) becomes 0a
  5. 0a is appended to the builder
  6. The loop reads the second byte: 15
  7. String.format("%02x", 15) becomes 0f
  8. 0f is appended
  9. The final string is 0a0f

Now converting back:

byte[] result = hexToBytes("0a0f");

Using this method:

public static byte[] hexToBytes(String hex) {
    if (hex.length() % 2 != 0) {
        throw new IllegalArgumentException("Hex string must have an even length");
    }

    byte[] bytes = new byte[hex.length() / 2];
    for (int i = 0; i < hex.length(); i += 2) {
        String hexPair = hex.substring(i, i + 2);
        bytes[i / 2] = (byte) Integer.parseInt(hexPair, 16);
    }
    return bytes;
}

Step by step

  1. The string is 0a0f
  2. Its length is 4, which is valid because it is even
  3. A byte array of size 2 is created
  4. The loop starts at i = 0
  5. substring(0, 2) gives 0a
  6. Integer.parseInt("0a", 16) becomes 10
  7. That value is stored in bytes[0]
  8. The loop moves to i = 2
  9. substring(2, 4) gives 0f
  10. Integer.parseInt("0f", 16) becomes 15
  11. That value is stored in bytes[1]
  12. The final byte array is {10, 15}

Real World Use Cases

Hex conversion appears in many everyday programming tasks.

1. Displaying hash values

Hash algorithms return raw bytes, but developers usually print them as hex.

byte[] hash = messageDigest.digest(data);
String hexHash = bytesToHex(hash);

2. Logging binary data

When debugging file content, network packets, or cryptographic values, hex is easier to inspect than raw bytes.

3. Reading configuration values

Some systems store IDs, colors, keys, or binary tokens as hex strings in configuration files or environment variables.

4. Working with file signatures

Many file formats begin with fixed byte patterns. Hex makes those patterns readable.

Example:

  • PNG starts with bytes shown as 89504e47

5. Interfacing with APIs and protocols

Some APIs send binary payloads as hexadecimal text, especially in lower-level systems or device communication.

Take Quiz

Real Codebase Usage

In real Java projects, byte-to-hex conversion is usually wrapped in utility methods so the logic stays reusable and consistent.

Common patterns

Utility helper methods

Developers often create a small utility class:

public final class HexUtils {
    private HexUtils() {}

    public static String bytesToHex(byte[] bytes) {
        StringBuilder hex = new StringBuilder();
        for (byte b : bytes) {
            hex.append(String.format("%02x", b));
        }
        return hex.toString();
    }
}

Validation before parsing

When converting from text to bytes, code often checks:

  • string is not null
  • length is even
  • characters are valid hex digits

Error handling

If input comes from users or external systems, parsing can fail. Real code often throws a clear exception or returns a validation error.

Normalization

Many codebases normalize hex to lowercase or uppercase so logs and comparisons are consistent.

Guard clauses

A common style is to reject bad input early:

if (hex == null || hex.length() % 2 != 0) {
    throw new IllegalArgumentException("Invalid hex string");
}

This keeps the main conversion logic simpler.

Common Mistakes

1. Forgetting that one byte needs two hex characters

Broken idea:

byte[] bytes = new byte[hex.length()];

Why it is wrong:

  • Two hex characters represent one byte
  • The correct array length is hex.length() / 2

2. Not checking for odd-length hex strings

Broken code:

String hex = "abc";
byte[] bytes = hexToBytes(hex);

Why it is wrong:

  • abc has 3 characters
  • You cannot split it into full byte pairs

Fix:

if (hex.length() % 2 != 0) {
    throw new IllegalArgumentException("Hex string must have an even length");
}

3. Using toString() on a byte array

Broken code:

byte[] data = {10, 15};
System.out.println(data.toString());

Output will look like this:

[B@1a2b3c4d

Why it is wrong:

  • toString() on an array does not print its contents
  • Use a conversion method or Arrays.toString(data) for numeric output

4. Ignoring signed bytes in Java

Java bytes are signed, from -128 to 127. That can confuse beginners.

Example:

byte b = (byte) 255;
System.out.println(b); // prints -1

This does not mean the hex conversion is wrong. It is just how Java stores bytes.


5. Not validating invalid characters

Broken input:

String hex = "0g";

Why it is wrong:

  • g is not a valid hexadecimal digit
  • Valid hex digits are 0-9, a-f, and A-F

6. Assuming hex is the same as text encoding

Hex is not the same as UTF-8 or ASCII. It is just a textual representation of raw bytes.

For example:

  • text: Hi
  • bytes in UTF-8: 72 105
  • hex representation: 4869

These are related, but not the same thing.

Comparisons

ConceptPurposeExampleNotes
byte[]Stores raw binary data{10, 15}Actual data used by the program
Hex stringHuman-readable form of bytes0a0f2 hex characters per byte
Base64 stringCompact text encoding for binaryCg8=Shorter than hex, often used in APIs
Decimal outputNumeric display of values10 15Readable, but not standard for binary protocols

Hex vs Base64

FeatureHexBase64
ReadabilityVery easy to inspect byte-by-byteLess intuitive for manual inspection
SizeLarger outputSmaller output
Common useDebugging, hashes, low-level dataAPIs, file transfer, tokens
Mapping2 characters per byteAbout 4 characters per 3 bytes

Manual conversion vs library methods

ApproachProsCons
Manual loopEasy to learn and controlMore code to maintain
Utility/library methodCleaner in productionYou need to know the API

For learning, manual conversion is excellent because it shows exactly how hex encoding works.

Take Quiz

Cheat Sheet

Byte array to hex

public static String bytesToHex(byte[] bytes) {
    StringBuilder hex = new StringBuilder();
    for (byte b : bytes) {
        hex.append(String.format("%02x", b));
    }
    return hex.toString();
}

Hex to byte array

public static byte[] hexToBytes(String hex) {
    if (hex.length() % 2 != 0) {
        throw new IllegalArgumentException("Hex string must have an even length");
    }

    byte[] bytes = new byte[hex.length() / 2];
    for (int i = 0; i < hex.length(); i += 2) {
        bytes[i / 2] = (byte) Integer.parseInt(hex.substring(i, i + 2), 16);
    }
    return bytes;
}

Key rules

  • 1 byte = 2 hex characters
  • Valid hex digits: 0-9, a-f, A-F
  • Hex string length must be even
  • Java byte is signed, but hex still represents the correct underlying bits

Quick examples

bytesToHex(new byte[] {10, 15}); // "0a0f"
hexToBytes("0a0f");             // {10, 15}

Watch out for

  • Odd-length strings
  • Invalid characters like g or z
  • Confusing text encoding with hex encoding
  • Using toString() on arrays

FAQ

How do I convert bytes to a hex string in Java?

Loop through the byte array and format each byte as a two-character hexadecimal value using String.format("%02x", b).

How do I convert a hex string back to a byte array?

Read the string two characters at a time, parse each pair with base 16, and store the result in a byte[].

Why does each byte need two hex characters?

Because one hex character represents 4 bits, and one byte contains 8 bits.

Can a hex string use uppercase letters?

Yes. Both uppercase (A-F) and lowercase (a-f) are valid hex digits.

Why do some bytes print as negative numbers in Java?

Java byte values are signed, ranging from -128 to 127. The underlying binary data is still correct.

What happens if the hex string has an odd length?

It is invalid for byte conversion because bytes must be represented by pairs of hex characters.

Is hex the same as Base64?

No. Both represent binary data as text, but hex is more readable while Base64 is more compact.

Take Quiz

Mini Project

Description

Build a small Java utility that converts data between byte arrays and hexadecimal strings. This demonstrates both directions of conversion and adds input validation, which is common in real applications that handle hashes, file signatures, or encoded binary values.

Goal

Create a program that prints a byte array as a hex string, then converts that hex string back into the original byte array.

Requirements

  • Create a method that converts a byte[] to a hex string.
  • Create a method that converts a hex string to a byte[].
  • Reject hex strings with an odd number of characters.
  • In main, test both methods with sample data.
  • Print the original bytes, the hex string, and the restored bytes.
Take Quiz

Keep learning

Related questions

View more