4

I have a program that gets ids from a database returned as a byte[]. I want to use those ids (byte arrays) as keys to a map. By default this does not work because what is compared is "object equality" not "content equality".

The next thing I tried which seemed to work is instantiating a String with the new String(byte[]) constructor. While this seems to work I know I'm doing some potentially dodgy things. I am not specifying an encoding which relies on whatever the system default is. I also don't know if all byte sequences will have representation in every encoding.

Is "converting" byte[] to String for the purpose of doing a map.put() and map.get() safe? Are there edge cases I'm not considering where this approach would inadvertently create a collision (where 2 different byte[]'s with different content could become the same String).

Note: The map is stored in memory and only lives for a single application run. Simple wrapper class I wrote to make my life easier if this approach is viable:

public class Cache { Map<String, Set<String>> cache = new HashMap<String, Set<String>>(); public Cache() {} public void put(byte[] key, Set<String> value) { cache.put(new String(key), value); } public Set<String> get(byte[] key) { return cache.get(new String(key)); } } 
1

2 Answers 2

6

You should probably use Biginteger. It has a BigInteger(byte[]) constructor and has an effective comparison system.

Sign up to request clarification or add additional context in comments.

1 Comment

This seems pretty straightforward. I'm going to go with this unless there is a blatant reason not to. The only thing I could think being an issue is a byte array with contents with "leading" zeros but this shouldn't be the case for me where that is a reality. Thanks for the answer!
2

Could you not build a simple wrapper around your byte[] array instead?

Something akin to:

public class CacheKey { private final byte[] key; public CacheKey(byte[] key) { this.key = key; // You may want to do a defensive copy here } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } CacheKey cacheKey = (CacheKey) o; return Arrays.equals(key, cacheKey.key); } @Override public int hashCode() { return key != null ? Arrays.hashCode(key) : 0; } } 

And use that as the map key? It would be a little more lightweight than using the built in String object and makes the key type actually clear.

2 Comments

Hey this might work too. Does Arrays.hashCode(prim[]) produce a hash based on content of the array?
That hashcode and equals method were actually generated by my IDE. Arrays.hashcode() guarantees a call to Arrays.equals() between two arrays with the same hashcode will evaluate to true, so it must do.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.