addAll to Set is not adding the values in java - 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.

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.

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

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 ....

mutable fields for objects in a Java Set

Am I correct in assuming that if you have an object that is contained inside a Java Set<> (or as a key in a Map<> for that matter), any fields that are used to determine identity or relation (via hashCode(), equals(), compareTo() etc.) cannot be changed without causing unspecified behavior for operations on the collection? (edit: as alluded to in this other question)
(In other words, these fields should either be immutable, or you should require the object to be removed from the collection, then changed, then reinserted.)
The reason I ask is that I was reading the Hibernate Annotations reference guide and it has an example where there is a HashSet<Toy> but the Toy class has fields name and serial that are mutable and are also used in the hashCode() calculation... a red flag went off in my head and I just wanted to make sure I understood the implications of it.
The javadoc for Set says
Note: Great care must be exercised if
mutable objects are used as set
elements. The behavior of a set is not
specified if the value of an object is
changed in a manner that affects
equals comparisons while the object is
an element in the set. A special case
of this prohibition is that it is not
permissible for a set to contain
itself as an element.
This simply means you can use mutable objects in a set, and even change them. You just should make sure the change doesn't impact the way the Set finds the items. For HashSet, that would require not changing the fields used for calculating hashCode().
That is correct, it can cause some problems locating the map entry. Officially the behavior is undefined, so if you add it to a hashset or as a key in a hashmap, you should not be changing it.
Yes, that will cause bad things to happen.
// Given that the Toy class has a mutable field called 'name' which is used
// in equals() and hashCode():
Set<Toy> toys = new HashSet<Toy>();
Toy toy = new Toy("Fire engine", ToyType.WHEELED_VEHICLE, Color.RED);
toys.add(toy);
System.out.println(toys.contains(toy)); // true
toy.setName("Fast truck");
System.out.println(toys.contains(toy)); // false
In a HashSet/HashMap, you could mutate a contained object to change the results of compareTo() operation -- relative comparison isn't used to locate objects. But it'd be fatal inside a TreeSet/TreeMap.
You can also mutate objects that are inside an IdentityHashMap -- nothing other than object identity is used to locate contents.
Even though you can do these things with these qualifications, they make your code more fragile. What if someone wants to change to a TreeSet later, or add that mutable field to the hashCode/equality test?

Do containsAll() and retainAll() in the Collection interface address cardinality?

In Java, the containsAll and retainAll in the AbstractCollection class explicitly state that cardinality is not respected, so in other words it does not matter how many instances of a value are on each side. Since all Java collections in the standard library extend AbstractCollection, it is assumed that all of them work the same.
However, the documentation of these methods in the Collection interface does not say anything. Is one supposed to infer from AbstractCollection, or was this left unspecified on purpose to allow one to define collections that work differently?
For example, Bag in apache-collections explicitly states that it does respect cardinality, and claims that it violates the contract of the version from Collection (even though it doesn't really).
So, what are the semantics of these operations in Collection rather than in AbstractCollection?
Edit: Tho those who are wondering about why I would care, it's because as part of my Ph.D. work I demonstrated that developers don't expect the conformance violation in Apache, but I'm trying to understand why the Collection interface was left so ambiguous.
The javadocs for containsAll (in Collection) say:
Returns: true if this collection
contains all of the elements in the
specified collection
and for retainAll (in Collection):
Retains only the elements in this
collection that are contained in the
specified collection (optional
operation). In other words, removes
from this collection all of its
elements that are not contained in the
specified collection.
I read containsAll's contract to mean that calling a.containsAll(b) will return true, if and only if, calling a.contains(bElem) for each element bElem in b would return true. I would also take it to imply that a.containsAll(someEmptyCollection) would also return true. As you state the javadocs for AbstractCollection more explicitly state this:
This implementation iterates over the
specified collection, checking each
element returned by the iterator in
turn to see if it's contained in this
collection. If all elements are so
contained true is returned, otherwise
false.
I agree that the contact for Collection for containsAll sould be more explicit to avoid any possiblity for confusion. (And that the reading of the javadocs for AbstractCollection should NOT have been necessary to confirm ones understanding of Collection)
I would not have made an assumption with regard to number of duplicate elements after a call to retainAll. The stated contract in Collection (by my reading) doesn't imply either way how duplicates in either collection would be handled. Based on my reading of retainAll in collection multiple possible results of a.retainAll(b) are all reasonable:
result contains 1 of each element that has at least one copy in both a and b
result contains each element (including duplicates) that was in a, except those that are not in b
or even, result contains somewhere between 1 and the number of copies found in a of each element in a, except those not in b.
I would have expected either #1 or #2, but would assume any of the the three to be legal based on the contract.
The javadocs for AbstractCollection confirm that it uses #2:
This implementation iterates over this
collection, checking each element
returned by the iterator in turn to
see if it's contained in the specified
collection. If it's not so contained,
it's removed from this collection with
the iterator's remove method
Although since this isn't in my reading of the original Collection interface's contract, I wouldn't necessarily assume the behavior of Collection to generally be this way.
Perhaps you should consider submitting suggested updates to the JavaDoc once you're done.
As to 'why the Collection interface was left so ambiguous' - I seriously doubt it was intentionally done - probably just something that wasn't given its due priority when that part of the API's were being written.
I don't think Collection defines it this way or the other, but it simply became sort of a convention to follow AbstractCollection behavior, for example google-collections do: see their Multiset documentation (Multiset is what they call a Bag)

Categories