How to convert a byte array to a hex string in Java?

JavaBytearrayHex

Java Problem Overview


I have a byte array filled with hex numbers and printing it the easy way is pretty pointless because there are many unprintable elements. What I need is the exact hexcode in the form of: 3a5f771c

Java Solutions


Solution 1 - Java

From the discussion here, and especially this answer, this is the function I currently use:

private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] bytes) {
    char[] hexChars = new char[bytes.length * 2];
    for (int j = 0; j < bytes.length; j++) {
        int v = bytes[j] & 0xFF;
        hexChars[j * 2] = HEX_ARRAY[v >>> 4];
        hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
    }
    return new String(hexChars);
}

My own tiny benchmarks (a million bytes a thousand times, 256 bytes 10 million times) showed it to be much faster than any other alternative, about half the time on long arrays. Compared to the answer I took it from, switching to bitwise ops --- as suggested in the discussion --- cut about 20% off of the time for long arrays. (Edit: When I say it's faster than the alternatives, I mean the alternative code offered in the discussions. Performance is equivalent to Commons Codec, which uses very similar code.)

2k20 version, with respect to Java 9 compact strings:

private static final byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes(StandardCharsets.US_ASCII);
public static String bytesToHex(byte[] bytes) {
    byte[] hexChars = new byte[bytes.length * 2];
    for (int j = 0; j < bytes.length; j++) {
        int v = bytes[j] & 0xFF;
        hexChars[j * 2] = HEX_ARRAY[v >>> 4];
        hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
    }
    return new String(hexChars, StandardCharsets.UTF_8);
}

Solution 2 - Java

The Apache Commons Codec library has a Hex class for doing just this type of work.

import org.apache.commons.codec.binary.Hex;

String foo = "I am a string";
byte[] bytes = foo.getBytes();
System.out.println( Hex.encodeHexString( bytes ) );

Solution 3 - Java

The method javax.xml.bind.DatatypeConverter.printHexBinary(), part of the Java Architecture for XML Binding (JAXB), was a convenient way to convert a byte[] to a hex string. The DatatypeConverter class also included many other useful data-manipulation methods.

In Java 8 and earlier, JAXB was part of the Java standard library. It was deprecated with Java 9 and removed with Java 11, as part of an effort to move all Java EE packages into their own libraries. It's a long story. Now, javax.xml.bind doesn't exist, and if you want to use JAXB, which contains DatatypeConverter, you'll need to install the JAXB API and JAXB Runtime from Maven.

Example usage:

byte bytes[] = {(byte)0, (byte)0, (byte)134, (byte)0, (byte)61};
String hex = javax.xml.bind.DatatypeConverter.printHexBinary(bytes);

Will result in:

000086003D

This answer the same as this one.

Solution 4 - Java

Simplest solution, no external libs, no digits constants:

public static String byteArrayToHex(byte[] a) {
   StringBuilder sb = new StringBuilder(a.length * 2);
   for(byte b: a)
      sb.append(String.format("%02x", b));
   return sb.toString();
}

Solution 5 - Java

Here are some common options ordered from simple (one-liner) to complex (huge library). If you are interested in performance, see the micro benchmarks below.

Option 1: Code snippet - Simple (only using JDK/Android)

Option 1a: BigInteger

One very simple solution is to use the BigInteger's hex representation:

new BigInteger(1, someByteArray).toString(16);

Note that since this handles numbers not arbitrary byte-strings it will omit leading zeros - this may or may not be what you want (e.g. 000AE3 vs 0AE3 for a 3 byte input). This is also very slow, about 100x slower compared to option 2.

Option 1b: String.format()

Using the %X placeholder, String.format() is able to encode most primitive types (short, int, long) to hex:

String.format("%X", ByteBuffer.wrap(eightByteArray).getLong());
Option 1c: Integer/Long (only 4/8 Byte Arrays)

If you exclusively have 4 bytes arrays you can use the toHexString method of the Integer class:

Integer.toHexString(ByteBuffer.wrap(fourByteArray).getInt());

The same works with 8 byte arrays and Long

Long.toHexString(ByteBuffer.wrap(eightByteArray).getLong());

Option 2: Code snippet - Advanced

Here is a full featured, copy & pasteable code snippet supporting upper/lowercase and endianness. It is optimized to minimize memory complexity and maximize performance and should be compatible with all modern Java versions (5+).

private static final char[] LOOKUP_TABLE_LOWER = new char[]{0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66};
private static final char[] LOOKUP_TABLE_UPPER = new char[]{0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46};
        
public static String encode(byte[] byteArray, boolean upperCase, ByteOrder byteOrder) {

    // our output size will be exactly 2x byte-array length
    final char[] buffer = new char[byteArray.length * 2];

    // choose lower or uppercase lookup table
    final char[] lookup = upperCase ? LOOKUP_TABLE_UPPER : LOOKUP_TABLE_LOWER;

    int index;
    for (int i = 0; i < byteArray.length; i++) {
        // for little endian we count from last to first
        index = (byteOrder == ByteOrder.BIG_ENDIAN) ? i : byteArray.length - i - 1;
        
        // extract the upper 4 bit and look up char (0-A)
        buffer[i << 1] = lookup[(byteArray[index] >> 4) & 0xF];
        // extract the lower 4 bit and look up char (0-A)
        buffer[(i << 1) + 1] = lookup[(byteArray[index] & 0xF)];
    }
    return new String(buffer);
}

public static String encode(byte[] byteArray) {
    return encode(byteArray, false, ByteOrder.BIG_ENDIAN);
}

The full source code with Apache v2 license and decoder can be found here.

Option 3: Using a small optimized library: bytes-java

While working on my previous project, I created this little toolkit for working with bytes in Java. It has no external dependencies and is compatible with Java 7+. It includes, among others, a very fast and well tested HEX en/decoder:

import at.favre.lib.bytes.Bytes;
...
Bytes.wrap(someByteArray).encodeHex()

You can check it out on Github: bytes-java.

Option 4: Apache Commons Codec

Of course there is the good 'ol commons codecs. (warning opinion ahead) While working on the project outlined above I analyzed the code and was quite disappointed; a lot of duplicate unorganized code, obsolete and exotic codecs probably only useful for very few and quite over engineered and slow implementations of popular codecs (specifically Base64). I therefore would make an informed decision if you want to use it or an alternative. Anyways, if you still want to use it, here is a code snippet:

import org.apache.commons.codec.binary.Hex;
...
Hex.encodeHexString(someByteArray));

Option 5: Google Guava

More often than not you already have Guava as a dependency. If so just use:

import com.google.common.io.BaseEncoding;
...
BaseEncoding.base16().lowerCase().encode(someByteArray);

Option 6: Spring Security

If you use the Spring framework with Spring Security you can use the following:

import org.springframework.security.crypto.codec.Hex
...
new String(Hex.encode(someByteArray));

Option 7: Bouncy Castle

If you already use the security framework Bouncy Castle you can use its Hex util:

import org.bouncycastle.util.encoders.Hex;
...
Hex.toHexString(someByteArray);

Not Really Option 8: Java 9+ Compatibility or 'Do Not Use JAXBs javax/xml/bind/DatatypeConverter'

In previous Java (8 and below) versions the Java code for JAXB was included as runtime dependency. Since Java 9 and Jigsaw modularisation your code cannot access other code outside of it's module without explicit declaration. So be aware if you get an exception like:

java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException

when running on a JVM with Java 9+. If so then switch implementations to any of the alternatives above. See also this question.


Micro Benchmarks

Here are results from a simple JMH micro benchmark encoding byte arrays of different sizes. The values are operations per second, so higher is better. Note that micro benchmarks very often do not represent real world behavior, so take these results with a grain of salt.

| Name (ops/s)         |    16 byte |    32 byte |  128 byte | 0.95 MB |
|----------------------|-----------:|-----------:|----------:|--------:|
| Opt1: BigInteger     |  2,088,514 |  1,008,357 |   133,665 |       4 |
| Opt2/3: Bytes Lib    | 20,423,170 | 16,049,841 | 6,685,522 |     825 |
| Opt4: Apache Commons | 17,503,857 | 12,382,018 | 4,319,898 |     529 |
| Opt5: Guava          | 10,177,925 |  6,937,833 | 2,094,658 |     257 |
| Opt6: Spring         | 18,704,986 | 13,643,374 | 4,904,805 |     601 |
| Opt7: BC             |  7,501,666 |  3,674,422 | 1,077,236 |     152 |
| Opt8: JAX-B          | 13,497,736 |  8,312,834 | 2,590,940 |     346 |

Specs: JDK 8u202, i7-7700K, Win10, 24GB Ram. See the full benchmark here.

Solution 6 - Java

A Guava solution, for completeness:

import com.google.common.io.BaseEncoding;
...
byte[] bytes = "Hello world".getBytes(StandardCharsets.UTF_8);
final String hex = BaseEncoding.base16().lowerCase().encode(bytes);

Now hex is "48656c6c6f20776f726c64".

Solution 7 - Java

This simple oneliner works for me
String result = new BigInteger(1, inputBytes).toString(16);
EDIT - Using this will remove the leading zeros, but hey worked for my use-case. Thanks @Voicu for pointing it out

Solution 8 - Java

I would use something like this for fixed length, like hashes:

md5sum = String.format("%032x", new BigInteger(1, md.digest()));

Solution 9 - Java

Use DataTypeConverter classjavax.xml.bind.DataTypeConverter

String hexString = DatatypeConverter.printHexBinary(bytes[] raw);

Solution 10 - Java

I found three different ways here: http://www.rgagnon.com/javadetails/java-0596.html

The most elegant one, as he also notes, I think is this one:

static final String HEXES = "0123456789ABCDEF";
public static String getHex( byte [] raw ) {
	if ( raw == null ) {
		return null;
	}
	final StringBuilder hex = new StringBuilder( 2 * raw.length );
	for ( final byte b : raw ) {
		hex.append(HEXES.charAt((b & 0xF0) >> 4))
			.append(HEXES.charAt((b & 0x0F)));
	}
	return hex.toString();
}

Solution 11 - Java

At the minor cost of storing the lookup table this implementation is simple and very fast.

 private static final char[] BYTE2HEX=(
    "000102030405060708090A0B0C0D0E0F"+
    "101112131415161718191A1B1C1D1E1F"+
    "202122232425262728292A2B2C2D2E2F"+
    "303132333435363738393A3B3C3D3E3F"+
    "404142434445464748494A4B4C4D4E4F"+
    "505152535455565758595A5B5C5D5E5F"+
    "606162636465666768696A6B6C6D6E6F"+
    "707172737475767778797A7B7C7D7E7F"+
    "808182838485868788898A8B8C8D8E8F"+
    "909192939495969798999A9B9C9D9E9F"+
    "A0A1A2A3A4A5A6A7A8A9AAABACADAEAF"+
    "B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"+
    "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"+
    "D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF"+
    "E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF"+
    "F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF").toCharArray();
   ; 
   
  public static String getHexString(byte[] bytes) {
    final int len=bytes.length;
    final char[] chars=new char[len<<1];
    int hexIndex;
    int idx=0;
    int ofs=0;
    while (ofs<len) {
      hexIndex=(bytes[ofs++] & 0xFF)<<1;
      chars[idx++]=BYTE2HEX[hexIndex++];
      chars[idx++]=BYTE2HEX[hexIndex];
    }
    return new String(chars);
  }

Solution 12 - Java

We don't need to use any external library or to write code based on loops and constants.
Is enough just this:

byte[] theValue = .....
String hexaString = new BigInteger(1, theValue).toString(16);

Solution 13 - Java

Java 17 finally contains HexFormat class so you can simply do:

HexFormat.of().formatHex(bytes);

It supports configuration as lowercase/uppercase, delimiters, prefix, suffix etc.

Solution 14 - Java

How about this?

    String byteToHex(final byte[] hash)
    {
        Formatter formatter = new Formatter();
        for (byte b : hash)
        {
            formatter.format("%02x", b);
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }

Solution 15 - Java

HexFormat was added in Java 17:

String hex = HexFormat.of().formatHex(array);

Solution 16 - Java

public static String toHexString(byte[] bytes) {

	StringBuilder sb = new StringBuilder();

	if (bytes != null) 
		for (byte b:bytes) {

			final String hexString = Integer.toHexString(b & 0xff);

			if(hexString.length()==1)
				sb.append('0');

			sb.append(hexString);//.append(' ');
		}

	  return sb.toString();//.toUpperCase();
}

To use DatatypeConverter:

public String toHexString(byte... bytes) {

	return Optional.ofNullable(bytes)
			.filter(bs->bs.length>0)
			.map(DatatypeConverter::printHexBinary)
			.map(str->IntStream.range(0, str.length())
					.filter(i->(i%2)==0)		// take every second index
					.mapToObj(i->"0x" + str.substring(i, i+2))
					.collect(Collectors.joining(" ")))
			.orElse("");
}

Solution 17 - Java

Adding a utility jar for simple function is not good option. Instead assemble your own utility classes. following is possible faster implementation.

public class ByteHex {

	public static int hexToByte(char ch) {
		if ('0' <= ch && ch <= '9') return ch - '0';
		if ('A' <= ch && ch <= 'F') return ch - 'A' + 10;
		if ('a' <= ch && ch <= 'f') return ch - 'a' + 10;
		return -1;
	}
	
	private static final String[] byteToHexTable = new String[]
	{
	    "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F",
	    "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F",
	    "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
	    "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F",
	    "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F",
	    "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
	    "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D", "6E", "6F",
	    "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F",
	    "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
	    "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F",
	    "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF",
	    "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
	    "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF",
	    "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF",
	    "E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
	    "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF"
	};
	
	private static final String[] byteToHexTableLowerCase = new String[]
	{
	    "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0a", "0b", "0c", "0d", "0e", "0f",
	    "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1a", "1b", "1c", "1d", "1e", "1f",
	    "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2a", "2b", "2c", "2d", "2e", "2f",
	    "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3a", "3b", "3c", "3d", "3e", "3f",
	    "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4a", "4b", "4c", "4d", "4e", "4f",
	    "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5a", "5b", "5c", "5d", "5e", "5f",
	    "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6a", "6b", "6c", "6d", "6e", "6f",
	    "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7a", "7b", "7c", "7d", "7e", "7f",
	    "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8a", "8b", "8c", "8d", "8e", "8f",
	    "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9a", "9b", "9c", "9d", "9e", "9f",
	    "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "aa", "ab", "ac", "ad", "ae", "af",
	    "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "b9", "ba", "bb", "bc", "bd", "be", "bf",
	    "c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf",
	    "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "da", "db", "dc", "dd", "de", "df",
	    "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", "e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef",
	    "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "fa", "fb", "fc", "fd", "fe", "ff"
	};
	
	public static String byteToHex(byte b){
		return byteToHexTable[b & 0xFF];
	}
	
	public static String byteToHex(byte[] bytes){
		if(bytes == null) return null;
		StringBuilder sb = new StringBuilder(bytes.length*2);
		for(byte b : bytes) sb.append(byteToHexTable[b & 0xFF]);
		return sb.toString();
	}
	
	public static String byteToHex(short[] bytes){
		StringBuilder sb = new StringBuilder(bytes.length*2);
		for(short b : bytes) sb.append(byteToHexTable[((byte)b) & 0xFF]);
		return sb.toString();
	}
	
	public static String byteToHexLowerCase(byte[] bytes){
		StringBuilder sb = new StringBuilder(bytes.length*2);
		for(byte b : bytes) sb.append(byteToHexTableLowerCase[b & 0xFF]);
		return sb.toString();
	}
	
	public static byte[] hexToByte(String hexString) {
		if(hexString == null) return null;
		byte[] byteArray = new byte[hexString.length() / 2];
		for (int i = 0; i < hexString.length(); i += 2) {
			byteArray[i / 2] = (byte) (hexToByte(hexString.charAt(i)) * 16 + hexToByte(hexString.charAt(i+1)));
		}
		return byteArray;
	}
	
	public static byte hexPairToByte(char ch1, char ch2) {
		return (byte) (hexToByte(ch1) * 16 + hexToByte(ch2));
	}
	

}

Solution 18 - Java

Here's yet another method using Streams:

private static String toHexString(byte[] bytes) {
	return IntStream.range(0, bytes.length)
    .mapToObj(i -> String.format("%02X", bytes[i]))
    .collect(Collectors.joining());
}

Solution 19 - Java

If you're using the Spring Security framework, you can use:

import org.springframework.security.crypto.codec.Hex

final String testString = "Test String";
final byte[] byteArray = testString.getBytes();
System.out.println(Hex.encode(byteArray));

Solution 20 - Java

I usually use the following method for debuf statement, but i don't know if it is the best way of doing it or not

private static String digits = "0123456789abcdef";

public static String toHex(byte[] data){
    StringBuffer buf = new StringBuffer();
    for (int i = 0; i != data.length; i++)
    {
        int v = data[i] & 0xff;
        buf.append(digits.charAt(v >> 4));
        buf.append(digits.charAt(v & 0xf));
    }
    return buf.toString();
}

Solution 21 - Java

I prefer to use this:

final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] bytes, int offset, int count) {
    char[] hexChars = new char[count * 2];
    for ( int j = 0; j < count; j++ ) {
        int v = bytes[j+offset] & 0xFF;
        hexChars[j * 2] = hexArray[v >>> 4];
        hexChars[j * 2 + 1] = hexArray[v & 0x0F];
    }
    return new String(hexChars);
}

It is slightly more flexible adaptation of the accepted answer. Personally, I keep both the accepted answer and this overload along with it, usable in more contexts.

Solution 22 - Java

Ok so there are a bunch of ways to do this, but if you decide to use a library I would suggest poking about in your project to see if something has been implemented in a library that is already part of your project before adding a new library just to do this. For example if you don't already have

> org.apache.commons.codec.binary.Hex

maybe you do have...

> org.apache.xerces.impl.dv.util.HexBin

Solution 23 - Java

A small variant of the solution proposed by @maybewecouldstealavan, which lets you visually bundle N bytes together in the output hex string:

 final static char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
 final static char BUNDLE_SEP = ' ';

public static String bytesToHexString(byte[] bytes, int bundleSize /*[bytes]*/]) {
        char[] hexChars = new char[(bytes.length * 2) + (bytes.length / bundleSize)];
        for (int j = 0, k = 1; j < bytes.length; j++, k++) {
                int v = bytes[j] & 0xFF;
                int start = (j * 2) + j/bundleSize;

                hexChars[start] = HEX_ARRAY[v >>> 4];
                hexChars[start + 1] = HEX_ARRAY[v & 0x0F];

                if ((k % bundleSize) == 0) {
                        hexChars[start + 2] = BUNDLE_SEP;
                }   
        }   
        return new String(hexChars).trim();    
}

That is:

bytesToHexString("..DOOM..".toCharArray().getBytes(), 2);
2E2E 444F 4F4D 2E2E

bytesToHexString("..DOOM..".toCharArray().getBytes(), 4);
2E2E444F 4F4D2E2E

Solution 24 - Java

Here is a java.util.Base64-like implementation, isn't it pretty?

import java.util.Arrays;

public class Base16/* a.k.a. Hex */ {
    public static class Encoder{
        private static char[] toLowerHex={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
        private static char[] toUpperHex={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
        private boolean upper;
        public Encoder(boolean upper) {
            this.upper=upper;
        }
        public String encode(byte[] data){
            char[] value=new char[data.length*2];
            char[] toHex=upper?toUpperHex:toLowerHex;
            for(int i=0,j=0; i<data.length; i++){
                int octet=data[i]&0xFF;
                value[j++]=toHex[octet>>4];
                value[j++]=toHex[octet&0xF];
            }
            return new String(value);
        }
        static final Encoder LOWER_CASE=new Encoder(false);
        static final Encoder UPPER_CASE=new Encoder(true);
    }
    public static Encoder getEncoder(){
        return Encoder.LOWER_CASE;
    }
    public static Encoder getUpperEncoder(){
        return Encoder.UPPER_CASE;
    }

    public static class Decoder{
      private static int maxIndex=102;
      private static int[] toIndex;
      static {
        toIndex=new int[maxIndex+1];
        Arrays.fill(toIndex, -1);
        char[] chars={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','a','b','c','d','e','f'};
        for(int i=0; i<chars.length; i++) {
          toIndex[(int)chars[i]]=i;
        }
      }
      public Decoder() {
      }
      public byte[] decode(String str) {
          char[] value=str.toCharArray();
          int start=0;
          if(value.length>2 && value[0]=='0' && (value[1]=='x' || value[1]=='X')) {
            start=2;
          }
          int byteLength=(value.length-start)/2; // ignore trailing odd char if exists
          byte[] data=new byte[byteLength];
          for(int i=start,j=0;i<value.length;i+=2,j++){
              int i1;
              int i2;
              char c1=value[i];
              char c2=value[i+1];
              if(c1>maxIndex || (i1=toIndex[(int)c1])<0 || c2>maxIndex || (i2=toIndex[(int)c2])<0) {
                throw new IllegalArgumentException("Invalid character at "+i);
              }
              data[j]=(byte)((i1<<4)+i2);
          }
          return data;
      }
      static final Decoder IGNORE_CASE=new Decoder();
  }
  public static Decoder getDecoder(){
      return Decoder.IGNORE_CASE;
  }
}

Solution 25 - Java

Can't find any solution on this page that doesn't

  1. Use a loop
  2. Use javax.xml.bind.DatatypeConverter which compiles fine but often throws java.lang.NoClassDefFoundError at runtime.

Here's a solution which doesn't have the flaws above(no promises mine doesn't have other flaws though)

import java.math.BigInteger;

import static java.lang.System.out;
public final class App2 {
    // | proposed solution.
    public static String encode(byte[] bytes) {          
        final int length = bytes.length;
        
        // | BigInteger constructor throws if it is given an empty array.
        if (length == 0) {
            return "00";
        }
        
        final int evenLength = (int)(2 * Math.ceil(length / 2.0));
        final String format = "%0" + evenLength + "x";         
        final String result = String.format (format, new BigInteger(bytes));
        
        return result;
    }

    public static void main(String[] args) throws Exception {
        // 00
        out.println(encode(new byte[] {})); 
        
        // 01
        out.println(encode(new byte[] {1})); 
        
        //203040
        out.println(encode(new byte[] {0x20, 0x30, 0x40})); 

        // 416c6c20796f75722062617365206172652062656c6f6e6720746f2075732e
        out.println(encode("All your base are belong to us.".getBytes()));
    }
}   

I couldn't get this under 62 opcodes, but if you can live without 0 padding in case the first byte is less than 0x10, then the following solution only uses 23 opcodes. Really shows how "easy to implement yourself" solutions like "pad with a zero if string length is odd" can get pretty expensive if a native implementation is not already available(or in this case, if BigInteger had an option to prefix with zeros in toString).

public static String encode(byte[] bytes) {          
    final int length = bytes.length;
    
    // | BigInteger constructor throws if it is given an empty array.
    if (length == 0) {
        return "00";
    }
    
    return new BigInteger(bytes).toString(16);
}

Solution 26 - Java

My solution is based on maybeWeCouldStealAVan's solution, but does not rely on any additionaly allocated lookup tables. It does not uses any 'int-to-char' casts hacks (actually, Character.forDigit() does it, performing some comparison to check what the digit truly is) and thus might be a bit slower. Please feel free to use it wherever you want. Cheers.

public static String bytesToHex(final byte[] bytes)
{
    final int numBytes = bytes.length;
    final char[] container = new char[numBytes * 2];

    for (int i = 0; i < numBytes; i++)
    {
        final int b = bytes[i] & 0xFF;

        container[i * 2] = Character.forDigit(b >>> 4, 0x10);
        container[i * 2 + 1] = Character.forDigit(b & 0xF, 0x10);
    }

    return new String(container);
}

Solution 27 - Java

Recently I had to implement a Hex converter to dump the byte stream into the log in Hex format. Initially I did it using Hex.encodeHex which has been already discussed in here.

But If you want to represent the byte array in a very presentable/readable way io.netty.buffer library could be a great use as it prints out the Hex as well the strings in it eliminating the non-printable characters.

Requirement was something like,

0010   56 56 09 35 32 f0 b2 00 50 4c 45 41 53 45 20 52   VV.52...PLEASE R
0020   45 2d 45 4e 54 45 52 20 4c 41 53 54 20 54 52 41   E-ENTER LAST TRA
0030   4e 53 41 43 54 49 4f 4e 00 04                     NSACTION..

The shortest way to do the same in a more presentable way using io.netty.buffer is

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;

void hexDump(byte[] buf) {
    ByteBuf byteBuf = Unpooled.wrappedBuffer(buf);
    log.trace("Bytes received (Hex)\n" + ByteBufUtil.prettyHexDump(byteBuf.slice()));
}

if you are using maven, include the below dependency in the pom.xml (check for the latest version in the netty page)

<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-buffer</artifactId>
    <version>4.1.68.Final</version>
</dependency>

output was:

         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000010| 40 40 b3 f3 80 f3 80 f3 80 f1 48 f1 41 f1 4e f1 |@@........H.A.N.|
|00000020| 47 f1 49 f1 4e f1 47 b5 f1 52 f1 4f f1 43 f1 4b |G.I.N.G..R.O.C.K|
|00000030| f3 80 f3 80 41 b4 40 40 f3 80 f3 80 40 f3 80 04 |....A.@@....@...|
+--------+-------------------------------------------------+----------------+

For your reference, the long way (may not be the most efficient) using the discussed methods in the answers is,

public static String hexDump(byte[] buf) throws DecoderException
{
    ByteBuffer byteBuf = ByteBuffer.wrap(buf);
	char[] result = Hex.encodeHex(byteBuf);

	String bin = new String(result).toUpperCase();
	String str = new String(Hex.decodeHex(bin), StandardCharsets.UTF_8);

	str = str.replaceAll("[^!-~]", ".");
	StringBuilder out = new StringBuilder();
	int bytes_per_line = 16;

	for (int pos = 0; pos < str.length(); pos += bytes_per_line) {
		out.append(String.format("%04X   ", pos));
		if (2 * (pos + bytes_per_line) >= bin.length()) {
			out.append(String.format("%-" + 2 * bytes_per_line + "s", bin.substring(2 * pos)).replaceAll("..", "$0 "));
		} else {
			out.append(bin.substring(2 * pos, 2 * (pos + bytes_per_line)).replaceAll("..", "$0 "));
		}
		out.append("   ");
		if (pos + bytes_per_line > str.length()) {
			out.append(str.substring(pos));

		} else {
			out.append(str.substring(pos, pos + bytes_per_line));
		}
		out.append("\n");
	}

	return out.toString();
}

Solution 28 - Java

If you're looking for a byte array exactly like this for python, I have converted this Java implementation into python.

class ByteArray:

@classmethod
def char(cls, args=[]):
	cls.hexArray = "0123456789ABCDEF".encode('utf-16')
	j = 0
	length = (cls.hexArray)

	if j < length:
		v = j & 0xFF
		hexChars = [None, None]
		hexChars[j * 2] = str( cls.hexArray) + str(v)
		hexChars[j * 2 + 1] = str(cls.hexArray) + str(v) + str(0x0F)
		# Use if you want...
		#hexChars.pop()

	return str(hexChars)

array = ByteArray()
print array.char(args=[])

Solution 29 - Java

  public static byte[] hexStringToByteArray(String s) {
    int len = s.length();
    byte[] data = new byte[len / 2];
    for (int i = 0; i < len; i += 2) {
      data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
        + Character.digit(s.charAt(i+1), 16));
    }
  return data;
  } 

Solution 30 - Java

private static String bytesToHexString(byte[] bytes, int length) {
        if (bytes == null || length == 0) return null;

        StringBuilder ret = new StringBuilder(2*length);

        for (int i = 0 ; i < length ; i++) {
            int b;

            b = 0x0f & (bytes[i] >> 4);
            ret.append("0123456789abcdef".charAt(b));

            b = 0x0f & bytes[i];
            ret.append("0123456789abcdef".charAt(b));
        }

        return ret.toString();
    }

Solution 31 - Java

Converts bytes data to hex characters

@param bytes byte array to be converted to hex string
@return byte String in hex format
         
private static String bytesToHex(byte[] bytes) {
    char[] hexChars = new char[bytes.length * 2];
    int v;
    for (int j = 0; j < bytes.length; j++) {
        v = bytes[j] & 0xFF;
        hexChars[j * 2] = HEX_ARRAY[v >>> 4];
        hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
    }
    return new String(hexChars);
}

Solution 32 - Java

// Shifting bytes is more efficient // You can use this one too

public static String getHexString (String s) 
{
	byte[] buf = s.getBytes();

	StringBuffer sb = new StringBuffer();
	
	for (byte b:buf)
	{
		sb.append(String.format("%x", b));
	}
	

    	return sb.toString();
}

Solution 33 - Java

Just iterate over all bytes, convert them to a hex String using Integer.toString (Unfortunately, there is no Byte.toString with a radix parameter) and append them all to a StringBuilder.

byte[] arr;//set it to your value
StringBuilder sb=new StringBuilder(arr.length*2);//1 byte...2 hex digits
for(int i=0;i<arr.length;i++){
  sb.append(Integer.toString(arr[i],16));
}
String hexValue=sb.toString();

This is similar to this answer from Pointer Null but it uses Integer.toString instead of String.format improving the performance.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAndreView Question on Stackoverflow
Solution 1 - JavamaybeWeCouldStealAVanView Answer on Stackoverflow
Solution 2 - JavachoobanView Answer on Stackoverflow
Solution 3 - JavaPhoneixSView Answer on Stackoverflow
Solution 4 - JavaPointer NullView Answer on Stackoverflow
Solution 5 - JavaPatrick FavreView Answer on Stackoverflow
Solution 6 - JavaStephan202View Answer on Stackoverflow
Solution 7 - JavaeverconfusedGuyView Answer on Stackoverflow
Solution 8 - JavaUsagi MiyamotoView Answer on Stackoverflow
Solution 9 - JavaSoumyaanshView Answer on Stackoverflow
Solution 10 - JavaMichael BisbjergView Answer on Stackoverflow
Solution 11 - JavahigginseView Answer on Stackoverflow
Solution 12 - JavaMarianView Answer on Stackoverflow
Solution 13 - JavaSaljackView Answer on Stackoverflow
Solution 14 - JavaManan BakshiView Answer on Stackoverflow
Solution 15 - JavaEng.FouadView Answer on Stackoverflow
Solution 16 - JavaOleksandr PotomkinView Answer on Stackoverflow
Solution 17 - Javakrishna TelgaveView Answer on Stackoverflow
Solution 18 - JavaRon McLeodView Answer on Stackoverflow
Solution 19 - Javajava-addict301View Answer on Stackoverflow
Solution 20 - JavaSnoxView Answer on Stackoverflow
Solution 21 - JavaBamacoView Answer on Stackoverflow
Solution 22 - JavaAaron CooleyView Answer on Stackoverflow
Solution 23 - JavaCampaView Answer on Stackoverflow
Solution 24 - JavafuweichinView Answer on Stackoverflow
Solution 25 - JavaDmitryView Answer on Stackoverflow
Solution 26 - JavaNetherwireView Answer on Stackoverflow
Solution 27 - JavaSajithPView Answer on Stackoverflow
Solution 28 - JavaSkippsDevView Answer on Stackoverflow
Solution 29 - Javaç”°å’–å•¡View Answer on Stackoverflow
Solution 30 - JavakakopappaView Answer on Stackoverflow
Solution 31 - JavaRajneesh ShuklaView Answer on Stackoverflow
Solution 32 - JavaBluePurseView Answer on Stackoverflow
Solution 33 - Javadan1stView Answer on Stackoverflow