831

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

Top-Master
9,0316 gold badges51 silver badges96 bronze badges
asked Mar 11, 2012 at 13:06
5
  • 17
    Why not just give it a try first and show us what you've got. You've nothing to lose and all to gain. Integer has a toHexString(...) method that may help if this is what you're looking for. Also String.format(...) can do some neat formatting tricks using the %2x code string. Commented Mar 11, 2012 at 13:09
  • 2
    possible duplicate of In Java, how do I convert a byte array to a string of hex digits while keeping leading zeros? Commented Feb 14, 2014 at 8:28
  • 1
    With the help of stream in Java 8, it can be simply implemented as: static String byteArrayToHex(byte[] a) { return IntStream.range(0, a.length) .mapToObj(i -> String.format("%02x", a[i])) .reduce((acc, v) -> acc + " " + v) .get(); } Commented Oct 10, 2019 at 1:59
  • 24
    Java 17 to the rescue: HexFormat.of().formatHex(bytes) Commented May 27, 2021 at 21:16
  • @tibetty You really call that "simple"? Commented Oct 11, 2022 at 11:03

34 Answers 34

1
2
1077

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);
}
Evgeniy Berezovsky
19.4k15 gold badges91 silver badges178 bronze badges
answered Mar 24, 2012 at 20:32
Sign up to request clarification or add additional context in comments.

20 Comments

I just found javax.xml.bind.DataTypeConverter, part of the standard distribution. Why doesn't this come up when you Google this kind of problem? Lots helpful tools, including String printHexBinary(byte[]) and byte[] parseHexBinary(String). printHexBinary is, however, much (2x) slower than the function in this answer. (I checked the source; it uses a stringBuilder. parseHexBinary uses an array.) Really, though, for most purposes it's fast enough and you probably already have it.
+1 for the answer since Android does not have DataTypeConverter
@maybeWeCouldStealAVan: JDK 7 is now open source. We should submit a patch to improve performance for printHexBinary?
javax.xml.bind.DataTypeConverter is being removed from Java 11.
Why is & 0xFF required in this line int v = bytes[j] & 0xFF;? Am I missing something or is it just unnecessary?
|
543

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 ) );
MultiplyByZer0
7,2493 gold badges35 silver badges49 bronze badges
answered Mar 11, 2012 at 13:18

13 Comments

@cytinus - My downvote occurred 4 months ago so I'm not entirely certain what I was thinking, but I was probably objecting to the size of the library. This is a small function within the program; there's no need to add such a bulky library to the project to perform it.
@ArtOfWarefare I agree, so instead of import org.apache.commons.codec.*; you could do import org.apache.commons.codec.binary.Hex;
@ArtOfWarfare I have to disagree. The only terrible thing is that the apache commons libraries aren't included by default with the JRE and JDK. There are some libraries that are so useful they really should be on your class path by default, and this is one of them.
I highly recommend this answer is swapped as the top answer. Always vote to use a well tested, performant, open source library over custom code which doesn't improve on it.
Or in case you use BouncyCastle (org.bouncycastle:bcprov-jdk15on), you can use this class : org.bouncycastle.util.encoders.Hex, with this method : String toHexString(byte[] data)
|
354

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.

MultiplyByZer0
7,2493 gold badges35 silver badges49 bronze badges
answered Feb 24, 2014 at 15:37

9 Comments

A good solution, though sadly not one that is valid in Android.
@Kazriko maybe you want to read code.google.com/p/dalvik/wiki/JavaxPackages. It is a way to get javax classes into Android. But if you only want convert to hex, it isn't worth the trouble.
DatatypeConverter is no longer accessible as of JDK 9
@PhoneixS It is still there, but not part of the default runtime (due to Java 9 modules).
don't rely on javax.xml.bind, it compiles fine but can be not be found at runtime. if you do, be prepared to handle java.lang.NoClassDefFoundError
|
294

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();
}
answered Oct 22, 2012 at 7:38

8 Comments

This is very slow, on average 1000 times slower (for 162 bytes long) than the one in the top response. Avoid using String.Format if performance matters.
Maybe slow. It's good for things happening occasionally, such as login or similar.
If it's slow, so what? In my use case it's just for a debug statement, so thanks for this code fragment.
Reusing a library by including an extra JAR files of several dozens kB would not exactly be efficient if all you need is this function (on some platforms like Android, the whole Jar gets included in the end application). And sometimes shorter and more clear code is better when performance is not needed.
@personne3000 maybe, but in that case you need stream support, not a single call feature. this one is easy to understand and remember, and therefore to maintain.
|
216

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 1d: JDK17+ HexFormat

Finally, JDK 17 offers first-level support of straight forward hex encoding with HexFormat:

HexFormat hex = HexFormat.of();
hex.formatHex(someByteArray)

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 overengineered 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 its 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, 24 GB Ram. See the full benchmark here.

Benchmark Update 2022

Here are results with current JMH 1.36, Java 17 and a higher end computer

| Name (ops/s) | 16 byte | 32 byte | 128 byte | 0.95 MB |
|----------------------|-----------:|-----------:|----------:|--------:|
| Opt1a: BigInteger | 2,941,403 | 1,389,448 | 242,096 | 5 |
| Opt1d: HexFormat | 32,635,184 | 20,262,332 | 7,388,135 | 922 |
| Opt2/3: Bytes Lib | 31,724,981 | 22,786,906 | 6,197,028 | 930 |

Specs: JDK temurin 17.0.6, Ryzen 5900X, Win11, 24 GB DDR4 Ram

answered Sep 26, 2019 at 13:36

3 Comments

Quite thorough! Since you're using Java 17, you might want to add HexFormat.of to the options for people using JDK17+.
Was not aware of that, thanks for the hint - will update the answer!
@Patrick Would you please let the HexFormat kick into the Benchmark?
65

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".

answered Apr 7, 2016 at 13:34

2 Comments

In Guava you can also use new HashCode(bytes).toString().
As of Guava 22.0 it is HashCode.fromBytes(checksum).toString()
50

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.

answered Sep 18, 2021 at 6:37

1 Comment

Finally, something that doesn't need an external library or is a broken solution
47

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

answered Nov 4, 2012 at 15:30

2 Comments

This oneliner drops leading zero bytes.
@Voicu ... And it will add a leading zero 50% of the time.
29

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

md5sum = String.format("%032x", new BigInteger(1, md.digest()));
answered Jan 22, 2017 at 6:00

Comments

24

Use DataTypeConverter classjavax.xml.bind.DataTypeConverter

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

answered May 12, 2016 at 13:43

1 Comment

Class removed in Java 11. See: JEP 320: Remove the Java EE and CORBA Modules
22

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();
}
answered Mar 11, 2012 at 13:11

3 Comments

Other methods were running on my 64 byte sample in 5ms, this one runs in 0ms. Probably best for lack of any other String functions like format.
if (raw == null) return null is not fail fast. Why would you ever use a null key?
I suppose it's a habit to input validate. In this case, we prevent any Null reference exception, and leave it up to the caller to handle bad data.
15

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);
 }
answered Jan 29, 2014 at 11:35

4 Comments

Why not initialize the BYTE2HEX array with a simple for cycle?
@icza Is that even possible with a static final (aka constant) field?
@nevelis It can be assigned in a static { } block.
@icza because its faster to hardcode a lookup table than to generate it. Here memory complexity is traded with time complexity, ie. needs more memory but faster (every so slightly on both ends)
12

HexFormat was added in Java 17:

String hex = HexFormat.of().formatHex(array);
answered Nov 3, 2021 at 14:55

Comments

9

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);
answered Apr 10, 2020 at 18:03

2 Comments

This is very similar to everconfusedGuy's Answer.
Careful you may end up skipping prefix characters in hashes that start with 0's because of how it's first stored as a BigInteger
8

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;
 }
JoseM
4,3022 gold badges26 silver badges35 bronze badges
answered Apr 21, 2015 at 22:44

Comments

8

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());
}
answered Dec 2, 2020 at 17:46

Comments

4
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("");
}
answered Jan 8, 2021 at 14:33

Comments

4

If you want to make it more readable and separate the bytes from each other, you can use the following code in Java 17+:

Update: As @BradHards mentioned, it can be simplified.

byte[] yourByteArray = { -128, 0, 127 };
// String hexString = new String(HexFormat.ofDelimiter(" ").formatHex(yourByteArray));
String hexString = HexFormat.ofDelimiter(" ").formatHex(yourByteArray);
// 80 00 7f
answered Oct 11, 2022 at 8:56

1 Comment

Why the new String(..) constructor? formatHex will return a String.
3

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));
 }
}
Suraj Rao
29.7k11 gold badges96 silver badges104 bronze badges
answered Jun 19, 2019 at 13:01

2 Comments

It is never a good choice to write your own "wheel", given there are implementations already available.
@DonaldDuck I agree with you in most cases. But sometimes adding a dependency to just use one function is not good either.
2

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

answered Sep 5, 2016 at 20:15

Comments

2

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));
answered Feb 13, 2019 at 17:51

Comments

1

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.

answered Jun 17, 2014 at 15:23

1 Comment

The original question was for byte[] to String. Look hex to bytes[] or ask a different question, @NonExistent.
1

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();
}
lucky1928
9,01110 gold badges55 silver badges110 bronze badges
answered Apr 21, 2014 at 15:48

1 Comment

If your debuffer has a bad day, try cluing in StringBuilder instantiation with a number of chars to support: StringBuilder buf = new StringBuilder(data.length * 2);.
1

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();
}
answered Oct 14, 2021 at 0:46

Comments

0

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
answered Mar 4, 2015 at 12:39

Comments

0
 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;
 } 
answered Nov 9, 2017 at 16:21

Comments

0
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();
 }
answered Feb 20, 2018 at 4:19

Comments

0

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);
}
answered May 14, 2018 at 23:21

Comments

0

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);
}
answered Jun 2, 2018 at 22:33

Comments

0
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);
}
Manaus
4055 silver badges9 bronze badges
answered Apr 30, 2019 at 7:09

Comments

1
2

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.