Using a byte array as Map key
Do you see any problem with using a byte array as Map key? I could also do new String(byte[])
and hash by String
but it is more straightforward to use byte[]
.
It's okay so long as you only want reference equality for your key - arrays don't implement "value equality" in the way that you'd probably want. For example:
byte[] array1 = new byte[1];
byte[] array2 = new byte[1];
System.out.println(array1.equals(array2));
System.out.println(array1.hashCode());
System.out.println(array2.hashCode());
prints something like:
false
1671711
11394033
(The actual numbers are irrelevant; the fact that they're different is important.)
Assuming you actually want equality, I suggest you create your own wrapper which contains a byte[]
and implements equality and hash code generation appropriately:
public final class ByteArrayWrapper
{
private final byte[] data;
public ByteArrayWrapper(byte[] data)
{
if (data == null)
{
throw new NullPointerException();
}
this.data = data;
}
@Override
public boolean equals(Object other)
{
if (!(other instanceof ByteArrayWrapper))
{
return false;
}
return Arrays.equals(data, ((ByteArrayWrapper)other).data);
}
@Override
public int hashCode()
{
return Arrays.hashCode(data);
}
}
Note that if you change the values within the byte array after using the ByteArrayWrapper
, as a key in a HashMap
(etc) you'll have problems looking up the key again... you could take a copy of the data in the ByteArrayWrapper
constructor if you want, but obviously that will be a waste of performance if you know you won't be changing the contents of the byte array.
EDIT: As mentioned in the comments, you could also use ByteBuffer
for this (in particular, its ByteBuffer#wrap(byte[])
method). I don't know whether it's really the right thing, given all the extra abilities that ByteBuffer
s have which you don't need, but it's an option.
The problem is that byte[]
uses object identity for equals
and hashCode
, so that
byte[] b1 = {1, 2, 3}
byte[] b2 = {1, 2, 3}
will not match in a HashMap
. I see three options:
- Wrapping in a
String
, but then you have to be careful about encoding issues (you need to make certain that the byte -> String -> byte gives you the same bytes). - Use
List<Byte>
(can be expensive in memory). - Do your own wrapping class, writing
hashCode
andequals
to use the contents of the byte array.
We can use ByteBuffer for this (This is basically the byte[] wrapper with a comparator)
HashMap<ByteBuffer, byte[]> kvs = new HashMap<ByteBuffer, byte[]>();
byte[] k1 = new byte[]{1,2 ,3};
byte[] k2 = new byte[]{1,2 ,3};
byte[] val = new byte[]{12,23,43,4};
kvs.put(ByteBuffer.wrap(k1), val);
System.out.println(kvs.containsKey(ByteBuffer.wrap(k2)));
will print
true