2

Can a StringBuffer as a key in a HashMap?
If so, what is the difference between using a String and a StringBuffer as the key?

JB.
  • 40,344
  • 12
  • 79
  • 106
sunish
  • 49
  • 1
  • 5

4 Answers4

5

Can a StringBuffer as a key in a HashMap?

No, since StringBuffer overrides neither equals nor hashCode, so it is not suitable as a HashMap key (recall that HashMap relies on those two methods to tell if a given key is present in the map).

Beyond that, StringBuffers are mutable, and you typically want Map keys to be immutable. From Map:

Note: great care must be exercised if mutable objects are used as map keys. The behavior of a map is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is a key in the map. A special case of this prohibition is that it is not permissible for a map to contain itself as a key. While it is permissible for a map to contain itself as a value, extreme caution is advised: the equals and hashCode methods are no longer well defined on such a map.

arshajii
  • 127,459
  • 24
  • 238
  • 287
1

No, you cannot, unless you want to distinguish between separate buffers instead of their contents. The StringBuffer class does not implement equals or hashCode which means it inherits these methods from Object. The Object implementation of these methods only distinguishes between object instances, not their contents.

In other words, if you would have two StringBuffer instances with the same contents, they would not be considered equal. Even weirder, if you would reinsert the same buffer with a different value, it would be considered equal to the previous one.


In general you should take care using mutable values as keys. Mutations will not alter the position in the Map, as the Map instance will not be notified of the change. In this case, since equals is not implemented anyway, this issue will not come up.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
0

All classes in java are intended to be used as hash keys, because all of them inherit the supermethod hashCode. Altough there are some cases in which, though it might compile well, would be quite weird, like Connection or Streams... or StringBuffer. This is why:

The main difference between String and StringBuffer is that a String is immutable by design, and it contains a proper implementation of hashCode. StringBuffers, instead, may change, and because of this, this class does not have a proper implementation of hashCode: It does not override the default implementation inherited from Object. Now you can see the consequences: A StringBuffer cannot contain a hash of high quality, nor coherent with its contents, damaging then the result of the hashing algorithm.

Little Santi
  • 8,563
  • 2
  • 18
  • 46
0

Yes, any object can be used as a key in a HashMap, although that may not be a good idea.

Class HashMap

Type Parameters:
    K - the type of keys maintained by this map
    V - the type of mapped values

From this SO answer:

When you put a key-value pair into the map, the hashmap will look at the hash code of the key, and store the pair in the bucket of which the identifier is the hash code of the key. (...) Looking at the above mechanism, you can also see what requirements are necessary on the hashCode() and equals() methods of keys (...)

Do notice, however, that StringBuffer does not override the required methods so your "key" will be the object's memory address. From the hashcode() docs:

(This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the JavaTM programming language.)

Meaning it's use as a key will be very different than String's:

Map<String, String> hashA = new HashMap<>();
a.put('a', 'a');
System.out.println(hashA.get('a')); //prints 'a'

Map<StringBuffer, String> hashB = new HashMap<>();
StringBuffer buffer = new StringBuffer('a');
hashB.put(buffer, 'a');
System.out.println(hashB.get(new StringBuffer('a'))); //prints null
System.out.println(hashB.get(buffer)); //prints 'a'
Marcelo
  • 4,580
  • 7
  • 29
  • 46