Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A Set in java never allows duplicates, but it takes StringBuffer objects with the same argument. Why?

public static void main(String[] args) {
    HashSet set = new HashSet(); 
    set.add(new StringBuffer("abc"));
    set.add(new StringBuffer("abc")); 
    set.add(new StringBuffer("abc"));
    set.add(new StringBuffer("abc")); 
    System.out.println(set); 
}

Output:

[abc,abc,abc,abc]

Here in above code I added object of StringBuffer("abc") many times and Set adds it but Set never adds duplicates.

like image 895
Nitesh Avatar asked Jul 04 '13 05:07

Nitesh


People also ask

Why set does not allow duplicates in Java?

The meaning of "sets do not allow duplicate values" is that when you add a duplicate to a set, the duplicate is ignored, and the set remains unchanged. This does not lead to compile or runtime errors: duplicates are silently ignored. Set is implemented like that to avoid duplication.

Does set allow duplicates in Java?

A Set is a Collection that cannot contain duplicate elements. It models the mathematical set abstraction. The Set interface contains only methods inherited from Collection and adds the restriction that duplicate elements are prohibited.

Can we store StringBuffer in set reason how do you do it?

Yes, you can but as the above answers state, you must write a Comparator. But the real question is why would you want to? The purpose of a StringBuffer is to modify the state while creating a string. Since it is a key in your SortedMap you shouldn't be modifying the key, so there is no point in saving the StringBuffer.

Does HashSet allow duplicates in Java?

Duplicates: HashSet doesn't allow duplicate values. HashMap stores key, value pairs and it does not allow duplicate keys.


4 Answers

StringBuffer does not override Object#equals() and Object#hashCode(), so identity of StringBuffer instances is based not on the contents of the buffer, but by the object's address in memory.*


* That identity is based on an address in memory is not strictly required by the JLS, but is a consequence of a typical Object#hashCode() implementation. From the JavaDoc:

As much as is reasonably practical, the hashCode method defined by class Object does return distinct integers for distinct objects. (This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the Java™ programming language.)

like image 99
Matt Ball Avatar answered Nov 03 '22 20:11

Matt Ball


StringBuffer doesn't override either equals or hashCode - so each object is only equal to itself.

This makes sense as StringBuffer is very much "mutable by design" - and equality can cause problems when two mutable objects are equal to each other, as one can then change. Using mutable objects as keys in a map or part of a set can cause problems. If you mutate one after insertion into the collection, that invalidates the entry in the collection as the hash code is likely to change. For example, in a map you wouldn't even be able to look up the value with the same object as the key, as the first test is by hash code.

StringBuffer (and StringBuilder) are designed to be very transient objects - create them, append to them, convert them to strings, then you're done. Any time you find yourself adding them to collections, you need to take a step back and see whether it really makes sense. Just occasionally it might do, but usually only when the collection itself is shortlived.

You should consider this in your own code when overriding equals and hashCode - it's very rarely a good idea for equality to be based on any mutable aspect of an object; it makes the class harder to use correctly, and can easily lead to subtle bugs which can take a long time to debug.

like image 40
Jon Skeet Avatar answered Nov 03 '22 20:11

Jon Skeet


Did it occur to you to see the equals() method (or the lack of it) in the StringBuffer? There lies the answer for you.

A Set or for that matter any hash based collection depends on the contract exposed by the equals() and hashcode() method on the Object for their behavior characteristic.

In your case since StringBuffer doesn't override these methods each StringBuffer instance that you create is different i.e new StringBuffer("abc") == new StringBuffer("abc") will return false.

I am curious as to why would someone add StringBuffer to a set.

like image 25
Scorpion Avatar answered Nov 03 '22 21:11

Scorpion


Most mutable object don't assume that if they happen to contain the same data they are the same. As they are mutable you can change the contents any time. i.e. it might be the same now, but not later, or it might be different now, but be the same later

BTW You shouldn't use StringBuffer if StringBuilder is an option. StringBuffer was replaced more than ten years ago.

like image 42
Peter Lawrey Avatar answered Nov 03 '22 19:11

Peter Lawrey