ArrayList.contains()

C

Colin Hemmings

Hi there I was wondering if anyone can help me using the contains method
for arratlists.

Basically, I have a class 'User' with attibutes 'userName, name, email'
I then have an Arraylist 'users' contains several users.

I have a method on another class which takes in a userName and returns
'true' if a user with that userName is in the 'users' list. The method
is below:

public boolean userExist(String userName)
{
boolean valid = false;
String temp = null;
for (int x=0; x<(users.size()); x++)
{
temp = ((User)users.get(x)).getUserName();
if (userName.equals(temp))
{
valid = true;
}

}
return valid;
}


This method works fine but I was wondering if I could do the same check
in fewer lines using the 'contains()' method. I have tried the following:

public boolean userExist(String userName)
{
boolean valid = false;
String temp = null;
valid = users.contains(userName);
return valid;
}

But although this compiles it doesnt work.

Would anybody be able to offer any suggestions?
 
J

janek

Colin Hemmings napisał(a):
Hi there I was wondering if anyone can help me using the contains method
for arratlists.

Basically, I have a class 'User' with attibutes 'userName, name, email'
I then have an Arraylist 'users' contains several users.

I have a method on another class which takes in a userName and returns
'true' if a user with that userName is in the 'users' list. The method
is below:

public boolean userExist(String userName)
{
boolean valid = false;
String temp = null;
for (int x=0; x<(users.size()); x++)
{
temp = ((User)users.get(x)).getUserName();
if (userName.equals(temp))
{
valid = true;
}

}
return valid;
}


This method works fine but I was wondering if I could do the same check
in fewer lines using the 'contains()' method. I have tried the following:

public boolean userExist(String userName)
{
boolean valid = false;
String temp = null;
valid = users.contains(userName);
return valid;
}

But although this compiles it doesnt work.

Would anybody be able to offer any suggestions?
you're comparing String object with User object so it cannot work
because of default equals(Object o) method implemention.
You should override equals(Object o) method in User class. (search
google for thousands of examples)
 
B

Bart Cremers

ArrayList.contains() works using the equals() method provided in your
class (User). If you don't provide a correct equals() implementation,
the default equals() will be used (x == y).

So to do it correct:

public class User {
....
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}

final User user = (User) o;

return !(userName != null ? !userName.equals(user.userName) :
user.userName != null);

}

public int hashCode() {
return (userName != null ? userName.hashCode() : 0);
}
}

I provided a hashCode as well because it used use to speed up things in
several collection classes.

public boolean userExist(String userName) {
boolean valid = false;
String temp = null;
valid = users.contains(new User(userName));
return valid;
}

Of course you could hack the equals method to allow comparing it to a
String, but that would break the general equals() contract.

public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o instanceof String) {
return o.equals(userName);
} else {
if (o == null || getClass() != o.getClass()) {
return false;
}

final User user = (User) o;

return !(userName != null ? !userName.equals(user.userName)
: user.userName != null);
}
}


regards,

Bart
 
T

Thomas Hawtin

janek said:
Colin Hemmings napisał(a):
you're comparing String object with User object so it cannot work
because of default equals(Object o) method implemention.
You should override equals(Object o) method in User class. (search
google for thousands of examples)

An overriding User.equals to return true for matching user names would
be just pure evil. (You would also have to override hashCode, to match
username.hashCode().)

A better approach is to use a Map. Use the user name as key and user as
value. LinkedHashMap can preserve order. Obviously that requires a bit
more work when inserting manipulating values, and the usernames would
need to be distinct. Perhaps a library, such as Apache Jakarta Commons
Collections will handle this sort of thing.

Tom Hawtin
 
T

tom fredriksen

Bart said:
ArrayList.contains() works using the equals() method provided in your
class (User). If you don't provide a correct equals() implementation,
the default equals() will be used (x == y).

I was wondering about this myself.

A lot of the collections classes takes objects as arguments to methods
such as contains() and others. What you are saying then, is that one
would need to create a new "pattern match" object with the values set
according to your search criteria. This object would then be passed to
the contains() method, which would start an object comparison process
where all objects in the list would be compared to the parameter object
with the equals() method. This means that overriding equals() in most
objects, if not all, is strongly advised.

Would you agree with such a statement?

/tom
 
B

Bart Cremers

I can agree with the statement that every stateful java object should
override both equals() and hashCode() following the general contract of
both methods. My second example is not what I would implement, I was
just providing a quick fix to the given problem.
A better strategy there is to introduce maps like Thomas pointed out.

Bart
 
J

John C. Bollinger

Bart said:
I can agree with the statement that every stateful java object should
override both equals() and hashCode() following the general contract of
both methods.

I strongly disagree. Most classes should *not* override equals, because
they have no sensible definition of object equality other than object
identity (x == y), and Object.equals() already provides an equality test
based on object identity. It is pointless (but not wrong) to override
Object.hashCode() without overriding Object.equals().
 
B

Bart Cremers

My definition of a "stateful" object is one that contains state, so
fields defining the contents of the object (POJO, ...). For these
objects it's almost always possible to define equality based on the
fields and therefor I strongly advice to override both equals() and
hashCode() (always BOTH).
Most of the time these kinds of objects will be used in some way of
storage mechanism (collections, db, ...), searching for existance of an
object will be simplified.
For any other object I'll never override equals() nor hashCode()
because, like you say, they do not have a better equality definition
then simple reference comparison (x == y).

Regards,

Bart
 
J

John C. Bollinger

Bart said:
My definition of a "stateful" object is one that contains state, so
fields defining the contents of the object (POJO, ...). For these
objects it's almost always possible to define equality based on the
fields and therefor I strongly advice to override both equals() and
hashCode() (always BOTH).

Your use of "stateful" was not lost on me, nor was the fact that given
at least one instance variable in a class, you can define an equality
relation based on the field values. For that matter, statefulness is
not required -- an equality relation based on field values is trivial if
there aren't any such values. No, my assertion is that it is typically
not sensible or useful to do define such a relation.
Most of the time these kinds of objects will be used in some way of
storage mechanism (collections, db, ...), searching for existance of an
object will be simplified.

Almost all objects are stateful by your definition, but most will never
be placed in a collection or array where anything other than object
identity matters. For instance, I may use a Collection to keep track of
several similar objects, but if I ever care to test for the presence of
some object, I usually want to know whether a *particular* object is
present, not whether some object with equivalent state is present.
(More often, I don't ask such questions at all.) Furthermore, I think
you are overstating your case. Your argument applies to the Collections
classes specifically. I don't see equals() having any bearing on
searching for objects in a DB, and definitely not on "...".

In any event, I think your focus on "stateful[ness]" is misplaced. I
think it was Chris Uppal who not so long ago argued here that object
state is an implementation detail in OO programming, and our attention
should instead be focused on object /behavior/. (I hope I'm
representing that accurately.) I tend to agree. On that basis, it's
not appropriate for an equals() method to attempt to answer the question
of whether some other object has the same state as this one. The
correct question is whether another object will behave the same way this
one does.

Furthermore, overriding equals() is problematic. For one thing, it
produces an inheritance problem: if you override equals() on class A in
the manner you describe, then no subclass of A can add instance
variables, implement your approach to equals(), and also retain the
symmetric nature that equals() is supposed to have. Any two of those
are exclusive of the other one.

Also, all Java objects have state that you cannot easily query, in the
form of a monitor. Even if two distinct objects of the same class have
exactly the same values for every field (object identity, even) they are
still not interchangeable when synchronization is involved.

Moreover, it is highly questionable how useful it is to query objects
with /mutable/ state about how their state compares with other objects',
because the answer may become stale even before it has been fully
determined. This is similar to the issues surrounding use of a mutable
object as a hash key, but considerably broader in scope. How is it
useful to even ask the question, much less answer it, if the answer has
an unknown duration of validity?
For any other object I'll never override equals() nor hashCode()
because, like you say, they do not have a better equality definition
then simple reference comparison (x == y).

"Any other object" being any class without instance variables? Those
are the absolute easiest ones to sensibly override equals() on.
 
B

Bart Cremers

John said:
Almost all objects are stateful by your definition, but most will never
be placed in a collection or array where anything other than object
identity matters. For instance, I may use a Collection to keep track of
several similar objects, but if I ever care to test for the presence of
some object, I usually want to know whether a *particular* object is
present, not whether some object with equivalent state is present.
(More often, I don't ask such questions at all.) Furthermore, I think
you are overstating your case. Your argument applies to the Collections
classes specifically. I don't see equals() having any bearing on
searching for objects in a DB, and definitely not on "...".

Well, for the case of DB searching I'm thinking of ORM systems like
hibernate instead of plain old JDBC. All projects I've been working on
last two years use some kind of ORM in between the OO layer and the
database and there object equality needs to be defined.
In any event, I think your focus on "stateful[ness]" is misplaced. I
think it was Chris Uppal who not so long ago argued here that object
state is an implementation detail in OO programming, and our attention
should instead be focused on object /behavior/. (I hope I'm
representing that accurately.) I tend to agree. On that basis, it's
not appropriate for an equals() method to attempt to answer the question
of whether some other object has the same state as this one. The
correct question is whether another object will behave the same way this
one does.

I agree on this one, object behavior is more important than object
equality, but implementing a correct equals() and hashCode() can
simplify the use of an object. With this I'm not saying you should
override them always.
Furthermore, overriding equals() is problematic. For one thing, it
produces an inheritance problem: if you override equals() on class A in
the manner you describe, then no subclass of A can add instance
variables, implement your approach to equals(), and also retain the
symmetric nature that equals() is supposed to have. Any two of those
are exclusive of the other one.

I don't see this one. It's pretty simple to extends the class and
override the equals() method.
Also, all Java objects have state that you cannot easily query, in the
form of a monitor. Even if two distinct objects of the same class have
exactly the same values for every field (object identity, even) they are
still not interchangeable when synchronization is involved.

Moreover, it is highly questionable how useful it is to query objects
with /mutable/ state about how their state compares with other objects',
because the answer may become stale even before it has been fully
determined. This is similar to the issues surrounding use of a mutable
object as a hash key, but considerably broader in scope. How is it
useful to even ask the question, much less answer it, if the answer has
an unknown duration of validity?

Well, that's a totally different subject and for sure not to purpose of
implementing and equals() method.
"Any other object" being any class without instance variables? Those
are the absolute easiest ones to sensibly override equals() on.

Easiest maybe, but it just makes no sense to me.

Bart
 
T

tom fredriksen

John said:
Almost all objects are stateful by your definition, but most will never
be placed in a collection or array where anything other than object
identity matters. For instance, I may use a Collection to keep track of
several similar objects, but if I ever care to test for the presence of
some object, I usually want to know whether a *particular* object is
present, not whether some object with equivalent state is present. (More
often, I don't ask such questions at all.) Furthermore, I think you are
overstating your case. Your argument applies to the Collections classes
specifically. I don't see equals() having any bearing on searching for
objects in a DB, and definitely not on "...".

I dont quite understand what you are getting at, identity and state are
two side of the same issue. It is not possible to have an identity and
not a state, because as soon as you give an object an identity you will
also have object state. Of course you could argue that the reference is
an objects identity, but that useless as you never f.ex give an Employee
object its reference as its employee number (the identity).

The question is whether equals represents state or identity and thats up
to the designer. Additionally, some objects are data oriented and some
objects are code oriented, so the data oriented objects would of course
need its own equals() and hashCode(), while the code oriented would not
need it.

Another question is if you want to use equals as a method for comparing
object for pure equality or for locating similar objects. Pure equality
is identical state or identity, while similarity is, well..., objects
that have the same values in certain fields.

E.g. a lot of the time equals is used to find one/many objects that
matches some predefined criteria, through in equals. So any object that
matches are what you are looking for. If not then the equals code is
wrong.
Furthermore, overriding equals() is problematic. For one thing, it
produces an inheritance problem: if you override equals() on class A in
the manner you describe, then no subclass of A can add instance
variables, implement your approach to equals(), and also retain the
symmetric nature that equals() is supposed to have. Any two of those
are exclusive of the other one.

No, its not problematic because any subclasses would have its own
extensions and its own idea of identity and state and would therefore
need to override both methods as well.

/tom
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,170
Latest member
Andrew1609
Top