Java ArrayList: contains() method returns false when arraylist contains the given object

Java ArrayList: contains() method returns false when arraylist contains the given object



I have a problem with the contains() method which returns false even though the ArrayList contains the given Object.
My code is following:


contains()


ArrayList


Object


String transaction = dbConnection.getPendingTransaction(username);
if (!onlineConnection.getSentTransactionRequests().contains(transaction))
onlineConnection.getSentTransactionRequests().add(transaction);

String packet = "RTR" + "_" + transaction[0] + "_" + transaction[2] +
"_" + transaction[3] + "_" + transaction[4];
onlineConnection.send(packet);



I have tried Thread.sleep() between iterations, so the ArrayList wasn't load as eagerly without success.


Thread.sleep()


ArrayList





equals and hashcode are apparently not your friends.
– haylem
Nov 13 '12 at 12:40


equals


hashcode





Please, please, please model your transaction as a proper object, and not as an array of strings. Then see @haylem's comment above.
– Perception
Nov 13 '12 at 12:50




5 Answers
5



The hashCode() and equals() of arrays are a bit broken when it comes to this (it is a long different discussion why).


hashCode()


equals()



A possible work around is to use ArrayList<ArrayList<String>> instead of ArrayList<String>, the equals() method for ArrayList will be as you expect it to.


ArrayList<ArrayList<String>>


ArrayList<String>


equals()


ArrayList



For example:


ArrayList<String> l1 = new ArrayList<>();
ArrayList<String> l2 = new ArrayList<>();
l1.add("asdf");
l2.add("asdf");
ArrayList<ArrayList<String>> coll = new ArrayList<>();
coll.add(l1);
System.out.println(coll.contains(l2));



Will yield true, as expected


true





If this is indeed the issue, the "long different discussion why" would be worth it.
– Don Roby
Nov 13 '12 at 12:48





@DonRoby: I believe the main reason it is still this way in java 7 is backward compability, to be honest. I believe that if the designers could change it without change the backward compability guideline of java - they would... But I am not an architect in Oracle, so I could be wrong. I also believe it is off topic.
– amit
Nov 13 '12 at 12:50






This is indeed the issue, and the reason is in the related question at stackoverflow.com/questions/8777257/….
– Don Roby
Nov 13 '12 at 12:56



Look at getPendingTransaction and getSentTransactionRequests if it should return SAME array and not create NEW one. Second, try to debug and look for arrays object id. If this is not same, but it should be (and contains same elements), try to workaround of this (for instance create comparator or List or something like).



The problem is that equals for arrays is defined to be reference equality. In other words, two different arrays that contain the same elements are NOT equal ... according to the equals method.


equals


equals



If you want equals for the "transaction" objects to be based on the equality of the strings, you need to create a custom class to hold the String, and override the equals method and the hashcode method.


equals


String


equals


hashcode



By the way, array equals(Object) method is not "a bit broken". The defined semantics of equals are simply reflecting the fact that any array object is inherently mutable.


equals(Object)


equals



It is because String transaction is object. And when you are calling contains list compares new object to some other one using equals method. Imagine it like doing


String transaction


contains


equals


new Object().equals(new Object())





Not entirely correct, note that if the collection contains "asdf" and you check for list.contains(new String("asdf")) you will get true.
– amit
Nov 13 '12 at 12:42


list.contains(new String("asdf"))





@amit Thank you. Updated my answer.
– Aleksandr M
Nov 13 '12 at 12:49



If you must use List<String>, possibly you are out of luck of using equals() or hashCode() it seems......


List<String>


equals()


hashCode()



Maybe you'd better create method to do compare your objects



Something like


public static boolean stringArrayListEquals(List<String> list, List<String> list2)
if (list.size() != list2.size()) return false;
for (int i = 0; i < list.size(); ++i)
if (!Arrays.equals(list.get(i), list2.get(i)) return false;

return true;



To test for contains(), you would need another loop...


contains()



Though you should seriously use List<List<String>> instead.


List<List<String>>






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)