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().
Related
I have this :
List<Data<Number, Number>> dataList = new ArrayList<XYChart.Data<Number,Number>>();
List<Data<Number, Number>> dataListSelected = new ArrayList<XYChart.Data<Number,Number>>();
I fill them with some Data<Number,Number> (in reality it is some Double). I do this for the two list.
for (XYZPointModel xyz : pm.getTopoPoints()) {
topoPoints.getData().add(new Data<Number, Number>(xyz.getX(),xyz.getY()));
}
and then i compare the two list. I want to know if i have some data in dataList that i dont have in dataListSelected.
System.out.println(dataList.removeAll(dataListSelected));
I got a FALSE.
Here the containt of my 2 list :
3 : [Data[18.367963,-0.832832,null], Data[30.165189,-0.461874,null], Data[18.808959,-6.575699,null]]
3 : [Data[18.367963,-0.832832,null], Data[30.165189,-0.461874,null], Data[18.808959,-6.575699,null]]
Btw, i don't know why i have a double, double, null. I dont know where the null come from.
Why my removeAll don't work ?
I presume Data is actually JavaFX.XYChart.Data, which has another object node as per docs. Therefore, this is null. I do not know if the "toString" method prints the value of the node object, but it sure seems like it.
ArrayList (and many other collections) use the contains() (which uses equals() method) to determine whether to remove an object in the remove()/removeAll() methods. if you check the following condition:
dataList.get(0).equals(dataListSelected.get(0))
my guess is it would be false, and therefore removeAll fails as well.
1、ArrayList use equals() to remove,
if (o.equals(elementData[i]))
return i;
but XYChart.Data didn't override equals() method, so Data will use method of Object
public boolean equals(Object obj) {
return (this == obj);
}
2、XYChart.Data has three properties
X xValue, Y yValue, Object extraValue
double, double, null
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
I have to make an ArrayList that contains an object, the object has one int for year lets say 1
and I don't what another object with the same year 1.
If one object has the int = 1 , i dont want another object with that int(1) in my list.
i want to deny it.
Should I try using equal?
something like
#Override
public boolean equals(Object o){
Object object = (Object)o;
return this.getInt.equals(object.getInt());
}
Either use a Set...which explicitly disallows duplicates, or check if the list contains the element on insertion.
#Override
public boolean add(T element) {
if(contains(element)) {
return false;
} else {
return super.add(element);
}
}
Overriding equals wouldn't get you very far, as you'd be overriding it for the List itself (i.e. you'd be checking if two lists were equal).
Perhaps you can try using a HashMap linked that links that "int" with the object. That could be:
Map<Integer, Object> map = new HashMap<>();
map.put(object.getInt(), object);
...
//Each time you put a new object you could try this:
if(!map.contains(object.getInt()))
map.put(object.getInt, object);
//And you can retrieve your object by an int
int a = 1;
Object obj = map.get(1);
In this case, as the value is of type int, you can use equal operator.
public boolean equals(Object o){
Object object = (Object)o;
return (this.getInt()==object.getInt());
}
For this kind of requirement, ArrayList is not suggestible. As mentioned in the other answers try using HashMap.
Yes, you can. When you call
myArrayList.contains(myObejct);
the ArrayList will invode myObejct's equals method. So you can tell if the object is already in you list.
And I think you can change you method a little,
#Override
public boolean equals(Object o){
if (!(o instanceof YourClass))
return false;
YourClass object = (YourClass)o;
return this.getInt.equals(object.getInt());
}
because if you don't, the method "getInt" might cause a MethodNotFound exception.
Well, that is one way to approach the problem.
Your equals will probably work provided that you change Object object = (Object)o; to cast to the real class.
However, equals ought to cope with the case where o is not of the expected type. The contract requires you should return false rather than throwing a ClassCastException ...
You would then use list.contains(o) to test if an object with the same int value exists in the list. For example:
if (!list.contains(o)) {
list.add(o);
}
But when you override equals, it is best practice to also override hashcode ... so that your class continues to satisfy the equals / hashcode invariants. (If you neglect to do that, hash-based data structures will break for your class.)
However, this won't scale well, because the contains operation on an ArrayList has to test each element in the list, one at a time. As the list gets longer, the contains call takes longer ... in direct proportion; i.e. O(N) ... using Big O complexity notation.
So it may be better to use a Set implementation of some kind instead on ArrayList. Fepending on which set implementation you choose, you will get complexity of O(1) or O(logN). But the catch is that you will either have to to implement hashcode (for a HashSet or LinkedHashSet), or implement either Comparable or a Comparator (for a TreeSet).
I want to retrive index of specific element of my list :
ArrayList<Field> list = new ArrayList<Field>();
list.addAll(profile.getFieldsList());
Object privacyName = "privacy";
int i = list.indexOf(privacyName);
boolean doesContain = list.contains(privacyName);
There is a field containing "privacy" in the list but i is always -1 and doesContain is always false. Why this search doesn't work ?
Why this search doesn't work ?
Because list contains instances of the Field class and you are calling the contains method passing a String instance.
To make it work you need to pass an instance of the Field class.
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
You need to override equals for logical equality or rely on default for reference equality.
In this case privacyName.equals(elementData[i]) is always false.
From the Java docs for indexOf:
Returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element.
So your list does not contain the object privacyName;
In ArrayList Index of method will based on equals method. In field class overide equals and hasCode method of Object class. And you told that "There is a field containing "privacy" in the list" . IndexOf Array will based on equals method. As #rocketboy's ans, u need to overide equals as well as hasCode method properly.
Why do I need to override the equals and hashCode methods in Java?
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);