0

We got these codes:

User user1=new User();
user1.setUserName("tomhand");

User user2=new User();
user2.setUserName("mira");

User user3=new User();
user3.setUserName("tomhand");

.......

List<User> list = new ArrayList<User>();
list.add(user1);
list.add(user2);
list.add(user3);
....

We can see that list contains 2 Users that have same user name tomhand Now, What is the simplest way to make the list become unique (ie, the list should not contain 2 users that have the same UserName)?

Tum
  • 3,614
  • 5
  • 38
  • 63
  • 6
    Use a `Set` and Override `equals` and `hashCode` in the `User` class. – SomeJavaGuy Jan 13 '16 at 15:13
  • 4
    One thing to note here is that putting mutable values into a hash-based set is not a good idea: changing properties of the values which change the hash code would invalidate the invariants of `HashSet`. – Andy Turner Jan 13 '16 at 15:19
  • use this solution http://stackoverflow.com/a/27872852/3215527 if you cannot/want not implement `equals` based on user name. – wero Jan 13 '16 at 15:21
  • It's not a good idea to do this with mutable objects, since the user names could be changed after adding them to the list. This would require the observer pattern or some similar code to be used to be notified of such changes to check again, if a user name occurs more than once. – fabian Jan 13 '16 at 15:25

3 Answers3

4

When add elements to the list (ArrayList) it does not perform any check on the existing element to check whether it is new element or already present. It will not be possible to use List and get the desired behavior directly.

You can use the Set collection for storing only the unique User instance based on the name attribute of it.

It is using the HashSet<User> implementation, which uses the hashcode() of the incoming object for storing them at a certain location. If the element is already present then it uses the equals() to compare the two objects.

Here is an sample example:

public class User {
  private String name;
  public User(String name) {
    this.name = name;
  }
  @Override
  public boolean equals(Object obj) {
    if (this == obj)
      return true;
    if (!(obj instanceof User))
      return false;
    User user = (User) obj;
    return user.name.equals(this.name);
  }
  @Override
  public int hashCode() {
    return name.hashCode()  ;
  }
}

class UserMain {
  public static void main(String[] args) {
    Set<User> set = new HashSet<>();
    set.add(new User("A"));
    set.add(new User("B"));
    set.add(new User("A"));
    System.out.println(set.size());
  }
}
YoungHobbit
  • 13,254
  • 9
  • 50
  • 73
1

Implement the Comparable interface in your User class and then use a Set<User> collection

Gianni B.
  • 2,691
  • 18
  • 31
  • 4
    Is the `hashCode()` and `equals()` pair not sufficient? – MrHug Jan 13 '16 at 15:14
  • 3
    If you're implementing `Comparable` you need to use a `TreeSet`. For `HashSet` you need `hashCode()` and `equals()`. – Kayaman Jan 13 '16 at 15:17
  • 1
    [The ordering needs to be consistent with equals](https://docs.oracle.com/javase/7/docs/api/java/util/TreeSet.html) for `TreeSet`, so you'd likely need to implement both; however, it is not necessary to define an ordering using `Comparable` simply to get uniqueness, since you can just use an unordered set like `HashSet`. – Andy Turner Jan 13 '16 at 15:17
  • @MrHug only the OP can respond to it: the Comparable interface garantee you also the ordering (in certain collections) – Gianni B. Jan 13 '16 at 15:20
  • 2
    Fair enough, it depends on the Set implementation as pointed out by @Kayaman – MrHug Jan 13 '16 at 15:22
  • 1
    @AndyTurner "The behavior of a set is well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of the Set interface." i.e. it will work, it will just be a rebel that doesn't care about contracts! – Kayaman Jan 13 '16 at 15:28
  • I am getting how `Comparable` can achieve the De-duplication here. It used for sorting the data. It needs the `equals()` and `hashCode()` as specified by @MrHug. – YoungHobbit Jan 13 '16 at 15:45
-1

Simple way use a Set, you'll have to overwrite equals and hashCode. Example Whenever you implement equals, you MUST also implement hashCode

public class User
{
private String username;
//other fields comes here

@Override
public int hashCode()
{
    final int prime = 31;
    int result = 1;
    result = prime * result
            + ((username == null) ? 0 : username.hashCode());
    return result;
}

@Override
public boolean equals(Object obj)
{
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    User other = (User) obj;
    if (username == null)
    {
        if (other.username != null)
            return false;
    } else if (!username.equals(other.username))
        return false;
    return true;
}

public String getUsername()
{
    return username;
}

public void setUsername(String username)
{
    this.username = username;
}

@Override
public String toString()
{
    return "User [username=" + username + "]";
}


public static void main(String args[])
{
    Set<User> users = new HashSet<User>();
    User user1=new User();
    user1.setUsername("tomhand");

    User user2=new User();
    user2.setUsername("mira");

    User user3=new User();
    user3.setUsername("tomhand");

    users.add(user1);
    users.add(user2);
    users.add(user3);

    System.out.println(users);

}
 }
adhg
  • 10,437
  • 12
  • 58
  • 94