Java: how to convert a byte array to a hex string?

To convert a byte array to a hexadecimal (hex) string in Java, you can use several methods depending on your needs for efficiency, readability, or Java version. Below are detailed approaches with examples:

1. Lookup Table Method (Efficient)

This method uses a pre-defined lookup table for fast conversion, avoiding expensive string operations.

public class HexConverter {
    private static final char[] HEX_ARRAY = "0123456789abcdef".toCharArray();

    public static String bytesToHex(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        for (int i = 0; i < bytes.length; i++) {
            int value = bytes[i] & 0xFF; // Convert to unsigned integer (0-255)
            hexChars[i * 2] = HEX_ARRAY[value >>> 4];     // High nibble
            hexChars[i * 2 + 1] = HEX_ARRAY[value & 0x0F]; // Low nibble
        }
        return new String(hexChars);
    }

    public static void main(String[] args) {
        byte[] bytes = {0x12, 0x34, (byte) 0xAB, (byte) 0xFF};
        String hexString = bytesToHex(bytes);
        System.out.println(hexString); // Output: 1234abff
    }
}

Key Points:

  • Efficiency: Direct array indexing for O(n) time complexity.
  • Case Handling: Use HEX_ARRAY = "0123456789ABCDEF".toCharArray() for uppercase.
  • Edge Cases: Handles empty arrays and negative byte values correctly.

2. String.format with StringBuilder (Readable)

Leverages String.format for simplicity, but less efficient due to repeated string operations.

public class HexConverter {
    public static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b & 0xFF)); // Lowercase
            // For uppercase: use "%02X"
        }
        return sb.toString();
    }

    public static void main(String[] args) {
        byte[] bytes = {0x12, 0x34, (byte) 0xAB};
        System.out.println(bytesToHex(bytes)); // Output: 1234ab
    }
}

Key Points:

  • Readability: Easy to understand but slower for large arrays.
  • Format Specifier: %02x ensures two-character padding (e.g., 0a instead of a).

3. Java 17+ HexFormat (Modern Approach)

Java 17 introduced java.util.HexFormat for streamlined conversions.

import java.util.HexFormat;

public class HexConverter {
    public static void main(String[] args) {
        byte[] bytes = {0x12, 0x34, (byte) 0xAB};
        HexFormat hexFormat = HexFormat.of();
        String hexString = hexFormat.formatHex(bytes);
        System.out.println(hexString); // Output: 1234ab
    }
}

Key Points:

  • Simplicity: Built-in class handles formatting.
  • Case Control: Use HexFormat.of().withUpperCase() for uppercase.
  • Delimiters: Supports adding delimiters between bytes (e.g., formatHex(bytes, " ")).

Comparison of Methods

MethodProsCons
Lookup TableFastest, no dependenciesMore code to write
String.formatSimple, readableSlower for large arrays
HexFormat (Java 17)Modern, conciseRequires Java 17+

Examples & Edge Cases

Example 1: Basic Conversion

byte[] bytes = {0x0A, 0x1B, (byte) 0xFF};
System.out.println(bytesToHex(bytes)); // Output: 0a1bff

Example 2: Empty Array

byte[] emptyBytes = {};
System.out.println(bytesToHex(emptyBytes)); // Output: (empty string)

Example 3: Negative Byte

byte negativeByte = (byte) 0x8F; // Interpreted as -113 in Java
System.out.println(bytesToHex(new byte[]{negativeByte})); // Output: 8f

Handling Uppercase

  • Lookup Table: Change HEX_ARRAY to uppercase characters.
  • String.format: Use %02X instead of %02x.
  • HexFormat: Use HexFormat.of().withUpperCase().

Summary

  • For Efficiency: Use the lookup table method.
  • For Readability: Use String.format with StringBuilder.
  • For Modern Codebases: Use HexFormat (Java 17+).
  • Always handle byte-to-integer conversion with & 0xFF to avoid sign extension issues.

Leave a Reply

Your email address will not be published. Required fields are marked *