Debug equals() and hashCode() in Eclipse - java

I have below code and I have placed break points on overridden equals() and hashCode() methods of ContainerBean. When I run below application in debug mode, debugger stops at hashCode() only for System.out.println line and not while trying to remove element from List.
import java.util.ArrayList;
import java.util.List;
public class ListRemovalDriver {
public static void main(String[] args) {
List<ContainerBean> remitClaims = new ArrayList<>();
ContainedBean addedRemit1 = new ContainedBean();
addedRemit1.setRemitId(12345L);
ContainerBean added1 = new ContainerBean();
added1.setRemitBean(addedRemit1);
remitClaims.add(added1);
ContainedBean removedRemit1 = new ContainedBean ();
removedRemit1.setRemitId(12345L);
ContainerBean removed1 = new ContainerBean ();
removed1.setRemitBean(removedRemit1);
System.out.println("List before valid removal" + remitClaims);
remitClaims.remove(removed1);
System.out.println("List after valid removal" + remitClaims);
}
}
Am I missing something?
Would overridden equals() in ContainerBean not be called while removing element from list?
EDIT
I forgot to mention that hashCode() and equals() are working as expected i.e. elements getting removed as per equals() logic but its only debugger that is not taking me there on list remove function call.

Since you did not give the code I have to guess: You did not override equals, but instead added an overload like this:
public boolean equals(ContainerBean c) { ... }
This will not work because equals(Object) is called.
Change your equals implementation to take an argument of type Object and it will both get called and stopped at in eclipse debugger.

Would overridden equals() in ContainerBean not be called while
removing element from list ?
Yes, when you are using remove(Object o), then equals() in ContainerBean will be called to check the equality of the object and then remove it from the list as mentioned in the ArrayListAPI below (emphasis mine):
Removes the first occurrence of the specified element from this list,
if it is present. If the list does not contain the element, it is
unchanged. More formally, removes the element with the lowest index i
such that (o==null ? get(i)==null : o.equals(get(i))) (if such an
element exists). Returns true if this list contained the specified
element (or equivalently, if this list changed as a result of the
call).
But, on the other side, when you are removing an element using the index of the list (i.e., using remove(int index)), then there will NOT be any equals() check.
You can look here

Source code of ArrayList from jdk 7,
ArrayList.remove(Object o)
it invokes equals method to verify the object to remove from the collection
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
source: ArrayList Source

Related

Checking if ArrayList<> cointains a object dont work

My app downloading a Events from sqldatabase and add it to ArrayList<>. It do aduplicate so I wrote:
public static ArrayList<Events> list = new ArrayList<Events>();
static void addevhlp(Events e){
if (list.contains(e)){
Log.d("","it cointains")
}
else {
list.add(e);
}
}
But it never say me the list cointans element. What I'm doing wrong?
you have to override equals in Events, and define when two events are equals. The default implementation checks for equal object's reference. For instance, if your Events class has an int id field
#Override
public boolean equals(Object o) {
if (!(o instanceof Events)) {
return false;
}
Events event = (Events) o;
return id == event.id;
}
You should overrides equals and hashCode in your Events object.
See :
Best implementation for hashCode method for detail about hashCode
According to the documentation about ArrayList.contains:
Returns true if this list contains the specified element. More
formally, returns true if and only if this list contains at least one
element e such that (o==null ? e==null : o.equals(e)).
So, contains uses the equals implementation of your Events class to check if it holds the object.
if (list.contains(e))
If the events e has the same Reference than the one you have in the ArrayList the contains will work.
but If you want to check if the value is the same, but with a different Reference, you have to check if the properties of your events are exists or equals.
or you can simply use LINQ with List instead of ArrayList
C# how to determine, whether ArrayList contains object with certain attribute

contains method in java

i know this is simple but im going crazy
public class CadastroPessoas {
Collection<Pessoa> lista;
Pessoa p;
public static void main(String[] args) {
CadastroPessoas p = new CadastroPessoas();
}
public CadastroPessoas() {
lista = new ArrayList<>();
for (int i = 0; i < 10; i++) {
p = new PessoaFisica();
p.setNome(String.format("name %02d", i));
p.setEmail(String.format("mail%02d#mail.com", i));
p.setTelefone(String.format("122312%02d", i));
if (!lista.contains(p)) {
lista.add(p);
}
}
for (Pessoa pessoa : lista) {
System.out.println(pessoa.toString());
}
} }
i want add various "PessoaFisica" to my collection but i need to check if this person exists, and with this code i just add the 1st one, what is wrong in my code
From the documentation (http://docs.oracle.com/javase/7/docs/api/java/util/Collection.html) about the contains method of the Collection interface:
Returns true if this collection contains the specified element. More
formally, returns true if and only if this collection contains at
least one element e such that (o==null ? e==null : o.equals(e)).
o.equals(e)
Calls the non-overridden method of the class Object
I suggest you to override the method equals, for example
public class Pessoa
{
#Override
public boolean equals(Pessoa pessoa)
{
//You check if the fields are equal, if not, return false
if(this.field != pessoa.field) return false;
else if(this.field2 != pessoa.field2) return false;
return true;
}
}
Two inputs from my side here.
1)You are probably using the wrong collection interface for your purpose here. If you need to prevent duplicates you might be better off using a Set eg. HashSet or TreeSet.
2)As you have been told, you will need to override equals method in PessoaFisica and implement your own identity check, while you are at it do not forget to override hashCode() method. There is a contract between equals and hashCode. Two equal objects must have equal hashCodes.Most IDEs will generate this code for you, in idea go to Code->Generate->HashCode And Equals. It will ask you the fields to include and auto generate the two methods.
from javadoc for the list interface :
boolean contains(Object o)
Returns true if this list contains the specified element. More formally, returns true if and only if this list contains at least one element e such that (o==null ? e==null : o.equals(e))
So, it looks like that you are not overriding the equals method in PessoaFisica class.

Do I use list.remove correctly?

Assume that I know that the list SomeList contains thatObj. Does the following code remove reference to thatObj from SomeList or not?
SomeClass el = (SomeClass) thatObj.clone();
SomeList.remove(el);
Can't find through the reference if this method compares objects somehow. Intuition suggests that it should use Object.equals which returns true if references point to the same object, hence this code will not work.
If not then an additional question: how to remove from list if don't have the reference but know all the members of the object in question?
Can't find through the reference if this method compares objects somehow. Intuition suggests that it should use Object.equals which returns true if references point to the same object, hence this code will not work.
Yes, you are right.
If not then an additional question: how to remove from list if don't have the reference but know all the members of the object in question?
Two possibilities:
override the equals method in your class, create a new instance with all known members and call remove passing the newly created instance as a parameter
iterate through all the objects inside the list and remove the one that has the members equal to the values you have
remove method internally uses the equals method to check for the object in the list. If equal returns true then it will be removed. Overriding the equals method will allow to remove the objects properly. For your reference here is the code of ArrayList remove method:
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
Override the equals method on the class - here is the javadoc. Also look at Overriding the java equals() method quirk and Overriding equals and hashCode in Java.
Search the list to find the member by returning the index, then get the object and remove it. You can also remove it by the index. The code
SomeList.indexOf()
could help you to get the index of the object that override equals() and hashCode().

ArrayList indexOf() returns wrong index?

I have a problem with ArrayList. I'm using ArrayList like this:
private ArrayList<Playlist> mPlaylists;
where Playlist is a class inherited from another ArrayList.
I do the following:
p = new Playlist(...some parameters...);
mPlaylists.add(p);
Later, when I use 'p' to get the index in the list:
int index = mPlaylists.indexOf(p);
an index of '1' is returned, even though inspection of the list clearly shows that it's index '4'.
Does anybody know why this fails?
Thanks.
B.R.
Morten
Edit:
Same problem without indexOf(), using equals():
private int GetIndex(Playlist playlist) {
for (int i = 0; i < mPlaylists.size(); i++) {
if (mPlaylists.get(i).equals(playlist)) {
return i;
}
}
return -1;
}
New edit:
This WORKS!:
private int getIndex(Playlist playlist) {
for (int i = 0; i < mPlaylists.size(); i++) {
if (mPlaylists.get(i) == playlist) {
return i;
}
}
return -1;
}
Solution:
As suggested, I changed the Playlist class to not enherit from ArrayList, but rather keeping an instance privately. It turned out that I only had to implement 4 ArrayList methods.
This does the trick; Now indexOf() returns the correct object!
Thanks to all contributors!
Most likely your PlayList messed up with the default ArrayList equals implementation, because the way indexOf is calculated to something like:
indexOf(Object o)
if( o == null ) then iterate until null is found and return that index
if( o != null ) iterate until o.equals( array[i] ) is found and return taht index
else return -1
end
So, you are doing something funny with your .equals method or your are accidentally inserting another element in the list when you think it is at the end.
EDIT
As per your edit... see? Your .equals() method is broken.
Consider doing a good review and make sure it adheres to the description defined in Object.equals
From the API:
int indexOf(Object o):
Returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element. More formally, returns the lowest index i such that (o==null ? get(i)==null : o.equals(get(i))), or -1 if there is no such index.
So the answer is that you need to override .equals() in Playlist.
There may be many reasons for this behavior:
1) If multiple elements in an ArrayList are equal (according to equals method), then the first one is returned. Maybe you simply have multiple identical objects.
2) Your PlayList class extends ArrayList (I am not sure it's a good idea). Therefore, if you didn't override the equals method, the comparison is based on the sequence of elements only. For example, any two empty PlayList instances will be considered equal.
3) If you DID override equals, check your implementation. It must return true for a comparison with the same reference, and in your case it doesn't.
I'm not sure why you are having this problem, but I think if I were you I would choose to use the newer Generic List to create your list like this:
List<Playlist> mPlaylists = new List<Playlist>();
p = new Playlist(<some parameters>);
mPlaylists.Add(p);

When you call remove(object o) on an arraylist, how does it compare objects?

When you call remove(object o) on an arraylist in java, how does it compare the objects to find the correct one to remove? does it use the pointer? or does it compare the objects using the interface Comparable?
ArrayList remove() relies on the objects implementation of the Equal method. If no implementation has been done then the object is removed by Object's implementation of Equals which indeed is the pointer comparison.
From the documentation on ArrayList -
More formally, removes the element with the lowest index i such that (o==null ? get(i)==null : o.equals(get(i))) (if such an element exists)
Object equal method documentation -
The equals method for class Object implements the most discriminating possible equivalence relation on objects; that is, for any non-null reference values x and y, this method returns true if and only if x and y refer to the same object (x == y has the value true).
You should always consult the API for this kind of information.
ArrayList.remove(Object o): Removes the first occurrence of the specified element from this list, if it is present. If the list does not contain the element, it is unchanged. More formally, removes the element with the lowest index i such that (o==null ? get(i)==null : o.equals(get(i))) (if such an element exists).
Perhaps you were confusing this with e.g. TreeSet:
java.util.TreeSet: Note that the ordering maintained by a set (whether or not an explicit comparator is provided) must be consistent with equals if it is to correctly implement the Set interface. (See Comparable or Comparator for a precise definition of consistent with equals.) This is so because the Set interface is defined in terms of the equals operation, but a TreeSet instance performs all element comparisons using its compareTo (or compare) method, so two elements that are deemed equal by this method are, from the standpoint of the set, equal.
(Unfortunately e.g. TreeSet.remove method itself doesn't have any explicit reminder of the above caveat, but at least it's prominently placed at the top of the class documentation)
An illustrative example
The following snippet illustrates the difference in behaviors between collections that use equals (such as an ArrayList) and collections that use compare/compareTo (such as a TreeSet).
import java.util.*;
public class CollectionEqualsCompareTo {
static void test(Collection<Object> col, Object o) {
col.clear();
col.add(o);
System.out.printf("%b %b %b %b%n",
col.contains(o),
col.remove(o),
col.contains(o),
col.isEmpty()
);
}
public static void main(String[] args) {
Object broken1 = new Comparable<Object>() {
// Contract violations!!! Only used for illustration!
#Override public boolean equals(Object o) { return true; }
#Override public int compareTo(Object other) { return -1; }
};
Object broken2 = new Comparable<Object>() {
// Contract violations!!! Only used for illustration!
#Override public boolean equals(Object o) { return false; }
#Override public int compareTo(Object other) { return 0; }
};
test(new ArrayList<Object>(), broken1); // true true false true
test(new TreeSet<Object>(), broken1); // false false false false
test(new ArrayList<Object>(), broken2); // false false false false
test(new TreeSet<Object>(), broken2); // true true false true
}
}
The docs answer your question:
Removes a single instance of the
specified element from this
collection, if it is present (optional
operation). More formally, removes an
element e such that (o==null ? e==null
: o.equals(e)), if the collection
contains one or more such elements.
It uses equals()
from the docs:
Removes the first occurrence of the specified element from this list, if it is present. If the list does not contain the element, it is unchanged. More formally, removes the element with the lowest index i such that (o==null ? get(i)==null : o.equals(get(i))) (if such an element exists). Returns true if this list contained the specified element (or equivalently, if this list changed as a result of the call).

Categories