What interface in Java can I use to store unique objects? - java

I need to create a class that will store a unique object elements. I don't need to sort these elements but they must be unique.
Can someone give me advice as to what interface I should be using? It was suggested to me by one person that I could use Set and then another person said Vector or List. Now I am totally confused :-(

Set is what exactly you are looking for
Set<Integer> uniqueValues = new HashSet<Integer>();
uniqueValues.add(1);
uniqueValues.add(2);
uniqueValues.add(3);
uniqueValues.add(2);// will be ignored

From the doc for Set:
A collection that contains no duplicate elements. More formally, sets
contain no pair of elements e1 and e2 such that e1.equals(e2), and at
most one null element. As implied by its name, this interface models
the mathematical set abstraction.
(my emphasis)
Note that these objects should not be mutable as to affect their equality. Otherwise you could insert an object, then change it such that it would equal() another object in the set. I wouldn't expect a Set object to enforce uniqueness retrospectively.

Well, you should Set collections like HashSet. Do remeber following points.
Don't forget to implement equals method in classes whose objects your Set will contain.
Also, implement hashcode method with a good algo, that equally devides your collection in buckets. you can do it by possibly taking into account a particular property of object that you consider in equals method.

You have to use Set. It was designed to store unique objects. More formally, sets contain no pair of elements e1 and e2 such that e1.equals(e2), and at most one null element. This is why you have to remember to implement equals method in class which objects will be stored in a collection.

use set interface for storing unique object ....

Related

How can we maintain unique object list without using set?

Suppose we have two employee instances having some common attributes like id,name,address (All values are same ).
I want unique objects list without implementing Set.
Please don’t explain the logic with Primitive data type ,I want the uniqueness with Object type.
Simple: you create a "collection" class that calls uses the equals() method of "incoming" objects to compare them against already stored objects.
If that method gives all false - no duplicate, you add to the collection. If true - not unique. No adding.
In other words - you re-invent the wheel and create something that resembles a Java set. Of course, with all the implicit drawbacks - such as repeating implementation bugs that were fixed in the Java set implementations 15 to 20 years ago.
If you don't want to use a Set, use a List. All you need to know to implement uniqueness checking logic is whatequals(Object other) method does:
Indicates whether some other object is "equal to" this one
Now you can test an incoming object against all objects currently on your list, and add it if a match is not found.
Obviously, performance of this method of maintaining a unique collection of objects is grossly inferior to both hash-based and ordering-based sets.
If you cannot use a Set for holding unique instances of your Employee class, you can use a List. This requires you to do two things:
Override equals() (and hashCode()) in Employee to contain the equality logic. This you would need even if you used a Set.
Each time you add items to the list, use List.contains() for checking whether an equal object is already in the list. The method will internally use your Employee.equals() implementation. Add an item only if it's not already in the list. Note that this method is quite inefficient as it needs to iterate through the whole list in worst case (when an item is not already in the list).

Can/should one write a Comparator consistent with Object's equals method

I have an object, Foo which inherits the default equals method from Object, and I don't want to override this because reference equality is the identity relation that I would like to use.
I now have a specific situation in which I would now like to compare these objects according to a specific field. I'd like to write a comparator, FooValueComparator, to perform this comparison. However, if my FooValueComparator returns 0 whenever two objects have the same value for this particular field, then it is incompatible with the equals method inherited from Object, along with all the problems that entails.
What I would like to do would be to have FooValueComparator compare the two objects first on their field value, and then on their references. Is this possible? What pitfalls might that entail (eg. memory locations being changed causing the relative order of Foo objects to change)?
The reason I would like my comparator to be compatible with equals is because I would like to have the option of applying it to SortedSet collections of Foo objects. I don't want a SortedSet to reject a Foo that I try to add just because it already contains a different object having the same value.
This is described in the documentation of Comparator:
The ordering imposed by a comparator c on a set of elements S is said to be consistent with equals if and only if c.compare(e1, e2)==0 has the same boolean value as e1.equals(e2) for every e1 and e2 in S.
Caution should be exercised when using a comparator capable of imposing an ordering inconsistent with equals to order a sorted set (or sorted map). Suppose a sorted set (or sorted map) with an explicit comparator c is used with elements (or keys) drawn from a set S. If the ordering imposed by c on S is inconsistent with equals, the sorted set (or sorted map) will behave "strangely." In particular the sorted set (or sorted map) will violate the general contract for set (or map), which is defined in terms of equals.
It short, if the implementation of Comparator is not consistent with equals method, then you should know what you're doing and you're responsible of the side effects of this design, but it's not an imposition to make the implementation consistent to Object#equals. Still, take into account that it is preferable to do it in order to not cause confusion for future coders that will maintain the system. Similar concept applies when implementing Comparable.
An example of this in the JDK may be found in BigDecimal#compareTo, which explicitly states in javadoc that this method is not consistent with BigDecimal#equals.
If your intention is to use a SortedSet<YourClass> then probably you're using the wrong approach. I would recommend using a SortedMap<TypeOfYourField, Collection<YourClass>> (or SortedMap<TypeOfYourField, YourClass>, in case there are no equals elements for the same key) instead. It may be more work to do, but it provides you more control of the data stored/retrieved in/from the structure.
You may have several comparators for a given class, i.e each per different field. In that case equals can not be reused. Therefore the answer is not necessarily. You should make them consistence however if your collection is stored in a sorted (map or tree) and the comperator is used to determined element position in that collection.
See documentation for details.

addAll to Set is not adding the values in java

I have a property in an Object(Obj1)
Set<AssignedService> serviceList;
public Set<AssignedService> getServiceList();
I am doing the below operation in certain instances
Obj1.getServiceList().clear();
Obj1.getServiceList().addAll(services);
where Services is also Set
But what I see as an end result is services set is having 4 objects/data elements
but Obj1.getServiceList() is returning an empty set after addAll
What's the issue here. is it a problem with AssignedService object since it doesn't implements IComparable
You should first read this excellent piece on .equals()
Then, as others have pointed out, check your implementation of equals() and .hashcode() on the AssignedService class. Most likely the root cause is found here.
You could also check the return value of the .addAll(...) call - false would indicate that the underlying Set isn't modified by the method call.
Cheers,
Check the implementation of equals() in AssignedService.
Set: A collection that contains no duplicate elements. More formally, sets contain no pair of elements e1 and e2 such that e1.equals(e2), and at most one null element. As implied by its name, this interface models the mathematical set abstraction.

object reference set in java

I need to create a Set of objects. The concern is I do not want to base the hashing or the equality on the objects' hashCode and equals implementation. Instead, I want the hash code and equality to be based only on each object's reference identity (i.e.: the value of the reference pointer).
I'm not sure how to do this in Java.
The reasoning behind this is my objects do not reliably implement equals or hashCode, and in this case reference identity is good enough.
I guess that java.util.IdentityHashMap is what you're looking for (note, there's no IdentityHashSet). Lookup the API documentation:
This class implements the Map interface with a hash table, using reference-equality in place of object-equality when comparing keys (and values). In other words, in an IdentityHashMap, two keys k1 and k2 are considered equal if and only if (k1==k2). (In normal Map implementations (like HashMap) two keys k1 and k2 are considered equal if and only if (k1==null ? k2==null : k1.equals(k2)).)
This class is not a general-purpose Map implementation! While this class implements the Map interface, it intentionally violates Map's general contract, which mandates the use of the equals method when comparing objects. This class is designed for use only in the rare cases wherein reference-equality semantics are required.
edit: See Joachim Sauer's comment below, it's really easy to make a Set based on a certain Map. You'd need to do something like this:
Set<E> mySet = Collections.newSetFromMap(new IdentityHashMap<E, Boolean>());
You could wrap your objects into a wrapper class which could then implement hashcode and equals based simply on the object's identity.
You can extend HashSet (or actually - AbstractSet) , and back it with IdentityHashMap which uses System.identityHashCode(object) instead of obj.hashCode().
You can simply google for IdentityHashSet, there are some implementations already. Or use Collections.newSetFromMap(..) as suggested by Joachim Sauer.
This of course should be done only if you are not in "possession" of your objects' classes. Otherwise just fix their hashCode()

Can I have a set containing identical elements?

It is convenient for me to use a set. I like how I can "add" ("remove") an element to (from) the set. It is also convenient to check if a given element is in the set.
The only problem, I found out that I cannot add a new element to a set if the set has already such an element. Is it possible to have "sets" which can contain several identical elements.
You must use MultiSet or HashMap, where you save count of elements.
p.s. with hashmap you still doing add/remove with O(log n) operations
http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/Multiset.html
A Set might not be the best choice of collections for you if you want duplicates. Sets, by definition, do not allow duplicates:
A collection that contains no duplicate elements. More formally, sets contain no pair of elements e1 and e2 such that e1.equals(e2), and at most one null element. As implied by its name, this interface models the mathematical set abstraction.
Unless you have a complex use case that really requires using a Set (in which case you can use a MultiSet as #Frostman describes above), you might be better off just using a List.
There is no need to store the elements several times if they are identical. If you would like to keep track of how many instances of each element you have, you'd better use a Map.
A Set by definition cannot have duplicate elements. "Duplicate" is defined by the element's equality (see its equals and hashCode methods). If you want duplicates, the use a Collection that allows duplicates, such as ArrayList.

Categories